[Spice-commits] 496 commits - .gitignore CODING_STYLE MAINTAINERS Makefile Makefile.hw Makefile.objs Makefile.target QMP/qmp-events.txt aio.c arch_init.c block-migration.c block.c block.h block/blkdebug.c block/blkverify.c block/iscsi.c block/qcow.c block/qcow2.c block/qcow2.h block/qed.c block/qed.h block/raw-posix-aio.h block/rbd.c block/sheepdog.c block/stream.c block/vdi.c block/vpc.c block/vvfat.c block_int.h blockdev.c blockdev.h bt-host.c buffered_file.c compatfd.c compiler.h configure console.h coroutine-ucontext.c cpu-exec.c cpus.c cutils.c default-configs/alpha-softmmu.mak default-configs/arm-softmmu.mak default-configs/i386-softmmu.mak default-configs/mips-softmmu.mak default-configs/mips64-linux-user.mak default-configs/mips64-softmmu.mak default-configs/mips64el-linux-user.mak default-configs/mips64el-softmmu.mak default-configs/mipsel-softmmu.mak default-configs/mipsn32-linux-user.mak default-configs/mipsn32el-linux-user.mak default-configs/pci.mak default-configs/ppc- softmmu.mak default-configs/ppc64-softmmu.mak default-configs/ppcemb-softmmu.mak default-configs/sparc64-softmmu.mak default-configs/x86_64-softmmu.mak docs/live-block-ops.txt docs/writing-qmp-commands.txt event_notifier.c event_notifier.h exec-obsolete.h exec.c fsdev/file-op-9p.h fsdev/virtfs-proxy-helper.c hmp-commands.hx hmp.c hmp.h hw/9pfs hw/a15mpcore.c hw/a9mpcore.c hw/ac97.c hw/acpi.c hw/acpi_piix4.c hw/adlib.c hw/ads7846.c hw/alpha_dp264.c hw/alpha_pci.c hw/alpha_typhoon.c hw/apb_pci.c hw/apic.c hw/apic.h hw/apic_common.c hw/apic_internal.h hw/apm.c hw/applesmc.c hw/arm-misc.h hw/arm11mpcore.c hw/arm_boot.c hw/arm_gic.c hw/arm_l2x0.c hw/arm_mptimer.c hw/arm_sysctl.c hw/arm_timer.c hw/armv7m.c hw/armv7m_nvic.c hw/bitbang_i2c.c hw/boards.h hw/bonito.c hw/ccid-card-emulated.c hw/ccid-card-passthru.c hw/ccid.h hw/cirrus_vga.c hw/cirrus_vga_template.h hw/collie.c hw/container.c hw/cs4231.c hw/cs4231a.c hw/debugcon.c hw/dec_pci.c hw/ds1225y.c hw/ds1338.c hw/e1000.c hw/ecc. c hw/eccmemctl.c hw/eepro100.c hw/empty_slot.c hw/es1370.c hw/escc.c hw/esp.c hw/etraxfs_eth.c hw/etraxfs_pic.c hw/etraxfs_ser.c hw/etraxfs_timer.c hw/exynos4210.c hw/exynos4210.h hw/exynos4210_combiner.c hw/exynos4210_fimd.c hw/exynos4210_gic.c hw/exynos4210_mct.c hw/exynos4210_pmu.c hw/exynos4210_pwm.c hw/exynos4210_uart.c hw/exynos4_boards.c hw/fdc.c hw/fmopl.c hw/framebuffer.c hw/fw_cfg.c hw/g364fb.c hw/grackle_pci.c hw/grlib_apbuart.c hw/grlib_gptimer.c hw/grlib_irqmp.c hw/gt64xxx.c hw/gumstix.c hw/gus.c hw/hda-audio.c hw/hid.h hw/highbank.c hw/hpet.c hw/hpet_emul.h hw/hw.h hw/i2c.c hw/i2c.h hw/i82374.c hw/i82378.c hw/i8254.c hw/i8254.h hw/i8259.c hw/i8259_common.c hw/i8259_internal.h hw/ide hw/integratorcp.c hw/intel-hda.c hw/intel-hda.h hw/ioapic.c hw/ioapic_common.c hw/ioapic_internal.h hw/ioh3420.c hw/isa-bus.c hw/isa.h hw/ivshmem.c hw/kvm hw/kvmclock.c hw/kvmclock.h hw/lan9118.c hw/lance.c hw/leon3.c hw/lm32_juart.c hw/lm32_pic.c hw/lm32_sys.c hw/lm32_timer.c hw/lm 32_uart.c hw/lm832x.c hw/loader.c hw/lsi53c895a.c hw/m48t59.c hw/macio.c hw/mainstone.c hw/marvell_88w8618_audio.c hw/max111x.c hw/max7310.c hw/mc146818rtc.c hw/mcf5206.c hw/mcf5208.c hw/milkymist-ac97.c hw/milkymist-hpdmc.c hw/milkymist-memcard.c hw/milkymist-minimac2.c hw/milkymist-pfpu.c hw/milkymist-softusb.c hw/milkymist-sysctl.c hw/milkymist-tmu2.c hw/milkymist-uart.c hw/milkymist-vgafb.c hw/milkymist-vgafb_template.h hw/mips_fulong2e.c hw/mips_jazz.c hw/mips_malta.c hw/mips_r4k.c hw/mipsnet.c hw/mpc8544_guts.c hw/msi.c hw/msi.h hw/msix.c hw/msix.h hw/mst_fpga.c hw/musicpal.c hw/nand.c hw/ne2000-isa.c hw/ne2000.c hw/nseries.c hw/omap_dss.c hw/omap_gpio.c hw/omap_intc.c hw/onenand.c hw/opencores_eth.c hw/openpic.c hw/openpic.h hw/parallel.c hw/pc.c hw/pc.h hw/pc_piix.c hw/pci.c hw/pci.h hw/pci_bridge.c hw/pci_ids.h hw/pcie.c hw/pcie.h hw/pckbd.c hw/pcnet-pci.c hw/pcnet.c hw/pcspk.c hw/pcspk.h hw/pflash_cfi02.c hw/piix4.c hw/piix_pci.c hw/pl011.c hw/pl022.c hw/pl031.c hw /pl041.c hw/pl050.c hw/pl061.c hw/pl080.c hw/pl110.c hw/pl181.c hw/pl190.c hw/ppc440.c hw/ppc440.h hw/ppc440_bamboo.c hw/ppc4xx_pci.c hw/ppc_newworld.c hw/ppc_prep.c hw/ppce500_pci.c hw/ppce500_spin.c hw/prep_pci.c hw/prep_pci.h hw/primecell.h hw/ptimer.c hw/ptimer.h hw/pxa2xx.c hw/pxa2xx_dma.c hw/pxa2xx_gpio.c hw/pxa2xx_keypad.c hw/pxa2xx_lcd.c hw/pxa2xx_mmci.c hw/pxa2xx_pcmcia.c hw/pxa2xx_pic.c hw/pxa2xx_timer.c hw/qdev-addr.c hw/qdev-monitor.c hw/qdev-properties.c hw/qdev.c hw/qdev.h hw/qxl.c hw/realview.c hw/realview_gic.c hw/rtl8139.c hw/s390-virtio-bus.c hw/s390-virtio-bus.h hw/s390-virtio.c hw/sb16.c hw/sbi.c hw/scsi-bus.c hw/scsi-disk.c hw/scsi-generic.c hw/scsi.h hw/serial.c hw/sga.c hw/sh_pci.c hw/sh_timer.c hw/slavio_intctl.c hw/slavio_misc.c hw/slavio_timer.c hw/sm501.c hw/smbios.c hw/smbus.c hw/smbus.h hw/smbus_eeprom.c hw/smc91c111.c hw/spapr.c hw/spapr_hcall.c hw/spapr_llan.c hw/spapr_pci.c hw/spapr_rtas.c hw/spapr_vio.c hw/spapr_vio.h hw/spapr_vscsi.c hw/spap r_vty.c hw/sparc32_dma.c hw/spitz.c hw/ssd0303.c hw/ssd0323.c hw/ssi-sd.c hw/ssi.c hw/ssi.h hw/stellaris.c hw/stellaris_enet.c hw/strongarm.c hw/sun4c_intctl.c hw/sun4m.c hw/sun4m_iommu.c hw/sun4u.c hw/sysbus.c hw/sysbus.h hw/tc6393xb.c hw/tcx.c hw/tmp105.c hw/tosa.c hw/tusb6010.c hw/twl92230.c hw/unin_pci.c hw/usb-audio.c hw/usb-bt.c hw/usb-bus.c hw/usb-ccid.c hw/usb-desc.c hw/usb-desc.h hw/usb-ehci.c hw/usb-hid.c hw/usb-hub.c hw/usb-msd.c hw/usb-musb.c hw/usb-net.c hw/usb-ohci.c hw/usb-serial.c hw/usb-uhci.c hw/usb-wacom.c hw/usb-xhci.c hw/usb.c hw/usb.h hw/versatile_pci.c hw/versatilepb.c hw/vexpress.c hw/vga-isa.c hw/vga-pci.c hw/vga.c hw/vga.h hw/vga_int.h hw/vga_template.h hw/vhost.c hw/vhost_net.c hw/virtex_ml507.c hw/virtio-blk.c hw/virtio-console.c hw/virtio-net.c hw/virtio-pci.c hw/virtio-serial-bus.c hw/virtio-serial.h hw/virtio.c hw/vmmouse.c hw/vmport.c hw/vmware_vga.c hw/vmware_vga.h hw/vt82c686.c hw/wdt_i6300esb.c hw/wdt_ib700.c hw/wm8750.c hw/xen_backend.c hw /xen_disk.c hw/xen_nic.c hw/xen_platform.c hw/xgmac.c hw/xilinx_axidma.c hw/xilinx_axienet.c hw/xilinx_ethlite.c hw/xilinx_intc.c hw/xilinx_timer.c hw/xilinx_uartlite.c hw/xio3130_downstream.c hw/xio3130_upstream.c hw/z2.c hw/zaurus.c include/qemu input.c iov.c json-lexer.c kvm-all.c kvm-stub.c kvm.h libcacard/Makefile linux-headers/asm-powerpc linux-headers/asm-s390 linux-headers/asm-x86 linux-headers/linux linux-user/elfload.c linux-user/main.c linux-user/mips64 linux-user/mipsn32 linux-user/qemu.h linux-user/signal.c linux-user/strace.c linux-user/syscall.c linux-user/syscall_defs.h main-loop.c main-loop.h memory.c memory.h migration-exec.c migration-fd.c migration-tcp.c migration-unix.c migration.c module.c module.h monitor.c monitor.h net.c net.h net/checksum.c net/socket.c net/tap.c net/tap.h notify.c notify.h os-posix.c pc-bios/README pc-bios/bamboo.dtb pc-bios/bamboo.dts pc-bios/bios.bin pc-bios/optionrom pc-bios/slof.bin pflib.c posix-aio-compat.c qapi-schema.json q emu-bridge-helper.c qemu-char.c qemu-char.h qemu-common.h qemu-config.c qemu-coroutine-int.h qemu-coroutine-sleep.c qemu-coroutine.h qemu-doc.texi qemu-file.h qemu-ga.c qemu-img.c qemu-io.c qemu-nbd.c qemu-option.c qemu-option.h qemu-options.hx qemu-queue.h qemu-thread-win32.c qemu-timer.c qemu-timer.h qemu-tool.c qerror.c qerror.h qmp-commands.hx qmp.c qom/Makefile qom/container.c qom/object.c qom/qom-qobject.c roms/SLOF roms/seabios scripts/check-qerror.sh slirp/ip_icmp.c slirp/misc.c sysemu.h target-arm/cpu.h target-arm/helper.c target-arm/machine.c target-arm/translate.c target-i386/cpuid.c target-i386/hyperv.c target-i386/hyperv.h target-i386/kvm.c target-i386/translate.c target-ppc/cpu.h target-ppc/helper.c target-ppc/helper.h target-ppc/kvm.c target-ppc/op_helper.c target-ppc/translate.c target-ppc/translate_init.c target-sparc/vis_helper.c tcg/arm test-qmp-input-visitor.c tests/Makefile tests/tcg trace-events ui/sdl.c ui/spice-core.c ui/vnc.c ui/vnc.h usb-bsd.c usb-l inux.c usb-redir.c vl.c vmstate.h xen-all.c xen-mapcache.c xen-stub.c

Gerd Hoffmann kraxel at kemper.freedesktop.org
Tue Feb 21 02:53:42 PST 2012


 .gitignore                               |    4 
 CODING_STYLE                             |    3 
 MAINTAINERS                              |   50 
 Makefile                                 |   18 
 Makefile.hw                              |    2 
 Makefile.objs                            |   19 
 Makefile.target                          |   46 
 QMP/qmp-events.txt                       |   53 
 aio.c                                    |    2 
 arch_init.c                              |   38 
 block-migration.c                        |    2 
 block.c                                  |  186 +
 block.h                                  |   12 
 block/blkdebug.c                         |    4 
 block/blkverify.c                        |    4 
 block/iscsi.c                            |  139 +
 block/qcow.c                             |  104 -
 block/qcow2.c                            |  194 +-
 block/qcow2.h                            |    9 
 block/qed.c                              |  125 +
 block/qed.h                              |    7 
 block/raw-posix-aio.h                    |    2 
 block/rbd.c                              |   24 
 block/sheepdog.c                         |    6 
 block/stream.c                           |  269 ++
 block/vdi.c                              |    8 
 block/vpc.c                              |  282 ++
 block/vvfat.c                            |    3 
 block_int.h                              |   55 
 blockdev.c                               |  359 +++
 blockdev.h                               |    8 
 bt-host.c                                |    1 
 buffered_file.c                          |    2 
 compatfd.c                               |    2 
 compiler.h                               |    4 
 configure                                |   87 
 console.h                                |    3 
 coroutine-ucontext.c                     |   10 
 cpu-exec.c                               |   10 
 cpus.c                                   |    6 
 cutils.c                                 |   35 
 default-configs/alpha-softmmu.mak        |    2 
 default-configs/arm-softmmu.mak          |    1 
 default-configs/i386-softmmu.mak         |    2 
 default-configs/mips-softmmu.mak         |    2 
 default-configs/mips64-linux-user.mak    |    1 
 default-configs/mips64-softmmu.mak       |    2 
 default-configs/mips64el-linux-user.mak  |    1 
 default-configs/mips64el-softmmu.mak     |    2 
 default-configs/mipsel-softmmu.mak       |    2 
 default-configs/mipsn32-linux-user.mak   |    1 
 default-configs/mipsn32el-linux-user.mak |    1 
 default-configs/pci.mak                  |    1 
 default-configs/ppc-softmmu.mak          |    4 
 default-configs/ppc64-softmmu.mak        |    1 
 default-configs/ppcemb-softmmu.mak       |    1 
 default-configs/sparc64-softmmu.mak      |    2 
 default-configs/x86_64-softmmu.mak       |    2 
 docs/live-block-ops.txt                  |   58 
 docs/writing-qmp-commands.txt            |    2 
 event_notifier.c                         |    4 
 event_notifier.h                         |   12 
 exec-obsolete.h                          |   46 
 exec.c                                   |   30 
 fsdev/file-op-9p.h                       |   12 
 fsdev/virtfs-proxy-helper.c              |   29 
 hmp-commands.hx                          |   56 
 hmp.c                                    |  180 +
 hmp.h                                    |    9 
 hw/9pfs/cofile.c                         |   14 
 hw/9pfs/virtio-9p-device.c               |   61 
 hw/9pfs/virtio-9p-handle.c               |    4 
 hw/9pfs/virtio-9p-local.c                |  357 +++
 hw/9pfs/virtio-9p.c                      |    3 
 hw/a15mpcore.c                           |  103 +
 hw/a9mpcore.c                            |   50 
 hw/ac97.c                                |   94 
 hw/acpi.c                                |    3 
 hw/acpi_piix4.c                          |   70 
 hw/adlib.c                               |    2 
 hw/ads7846.c                             |   27 
 hw/alpha_dp264.c                         |    3 
 hw/alpha_pci.c                           |    6 
 hw/alpha_typhoon.c                       |   26 
 hw/apb_pci.c                             |   88 
 hw/apic.c                                |  369 ---
 hw/apic.h                                |    1 
 hw/apic_common.c                         |  326 +++
 hw/apic_internal.h                       |  122 +
 hw/apm.c                                 |    3 
 hw/applesmc.c                            |   38 
 hw/arm-misc.h                            |   20 
 hw/arm11mpcore.c                         |   79 
 hw/arm_boot.c                            |   92 
 hw/arm_gic.c                             |   68 
 hw/arm_l2x0.c                            |   39 
 hw/arm_mptimer.c                         |   39 
 hw/arm_sysctl.c                          |   45 
 hw/arm_timer.c                           |   59 
 hw/armv7m.c                              |   33 
 hw/armv7m_nvic.c                         |   46 
 hw/bitbang_i2c.c                         |   28 
 hw/boards.h                              |    1 
 hw/bonito.c                              |   63 
 hw/ccid-card-emulated.c                  |   52 
 hw/ccid-card-passthru.c                  |   45 
 hw/ccid.h                                |   27 
 hw/cirrus_vga.c                          |  115 -
 hw/cirrus_vga_template.h                 |  102 +
 hw/collie.c                              |    3 
 hw/container.c                           |   20 
 hw/cs4231.c                              |   35 
 hw/cs4231a.c                             |   55 
 hw/debugcon.c                            |   36 
 hw/dec_pci.c                             |   86 
 hw/ds1225y.c                             |   37 
 hw/ds1338.c                              |   41 
 hw/e1000.c                               |   61 
 hw/ecc.c                                 |    3 
 hw/eccmemctl.c                           |   37 
 hw/eepro100.c                            |  211 +-
 hw/empty_slot.c                          |   22 
 hw/es1370.c                              |   79 
 hw/escc.c                                |   51 
 hw/esp.c                                 |   35 
 hw/etraxfs_eth.c                         |   41 
 hw/etraxfs_pic.c                         |   33 
 hw/etraxfs_ser.c                         |   27 
 hw/etraxfs_timer.c                       |   22 
 hw/exynos4210.c                          |  270 ++
 hw/exynos4210.h                          |  131 +
 hw/exynos4210_combiner.c                 |  469 ++++
 hw/exynos4210_fimd.c                     | 1928 ++++++++++++++++++++
 hw/exynos4210_gic.c                      |  458 ++++
 hw/exynos4210_mct.c                      | 1488 +++++++++++++++
 hw/exynos4210_pmu.c                      |  499 +++++
 hw/exynos4210_pwm.c                      |  422 ++++
 hw/exynos4210_uart.c                     |  676 +++++++
 hw/exynos4_boards.c                      |  177 +
 hw/fdc.c                                 |  114 -
 hw/fmopl.c                               |    4 
 hw/framebuffer.c                         |   12 
 hw/fw_cfg.c                              |   41 
 hw/g364fb.c                              |   55 
 hw/grackle_pci.c                         |   53 
 hw/grlib_apbuart.c                       |  138 +
 hw/grlib_gptimer.c                       |   40 
 hw/grlib_irqmp.c                         |   37 
 hw/gt64xxx.c                             |   47 
 hw/gumstix.c                             |    3 
 hw/gus.c                                 |   63 
 hw/hda-audio.c                           |   69 
 hw/hid.h                                 |   23 
 hw/highbank.c                            |  338 +++
 hw/hpet.c                                |  109 -
 hw/hpet_emul.h                           |    3 
 hw/hw.h                                  |  893 ---------
 hw/i2c.c                                 |  116 -
 hw/i2c.h                                 |   57 
 hw/i82374.c                              |  165 +
 hw/i82378.c                              |  277 ++
 hw/i8254.c                               |  131 -
 hw/i8254.h                               |   57 
 hw/i8259.c                               |  179 -
 hw/i8259_common.c                        |  161 +
 hw/i8259_internal.h                      |   82 
 hw/ide/ahci.c                            |   60 
 hw/ide/cmd646.c                          |   48 
 hw/ide/ich.c                             |   43 
 hw/ide/internal.h                        |   20 
 hw/ide/isa.c                             |   40 
 hw/ide/pci.c                             |    6 
 hw/ide/piix.c                            |  106 -
 hw/ide/qdev.c                            |  139 -
 hw/ide/via.c                             |   36 
 hw/integratorcp.c                        |   50 
 hw/intel-hda.c                           |  109 -
 hw/intel-hda.h                           |   25 
 hw/ioapic.c                              |  153 -
 hw/ioapic_common.c                       |  120 +
 hw/ioapic_internal.h                     |  102 +
 hw/ioh3420.c                             |   67 
 hw/isa-bus.c                             |   67 
 hw/isa.h                                 |   21 
 hw/ivshmem.c                             |   58 
 hw/kvm/apic.c                            |  147 +
 hw/kvm/clock.c                           |  129 +
 hw/kvm/clock.h                           |   24 
 hw/kvm/i8259.c                           |  138 +
 hw/kvm/ioapic.c                          |  125 +
 hw/kvmclock.c                            |  118 -
 hw/kvmclock.h                            |   24 
 hw/lan9118.c                             |  291 ++-
 hw/lance.c                               |   42 
 hw/leon3.c                               |    1 
 hw/lm32_juart.c                          |   29 
 hw/lm32_pic.c                            |   27 
 hw/lm32_sys.c                            |   37 
 hw/lm32_timer.c                          |   40 
 hw/lm32_uart.c                           |   29 
 hw/lm832x.c                              |   41 
 hw/loader.c                              |    6 
 hw/lsi53c895a.c                          |   40 
 hw/m48t59.c                              |   79 
 hw/macio.c                               |   51 
 hw/mainstone.c                           |    3 
 hw/marvell_88w8618_audio.c               |   46 
 hw/max111x.c                             |   47 
 hw/max7310.c                             |   43 
 hw/mc146818rtc.c                         |  110 -
 hw/mcf5206.c                             |    1 
 hw/mcf5208.c                             |    1 
 hw/milkymist-ac97.c                      |   27 
 hw/milkymist-hpdmc.c                     |   27 
 hw/milkymist-memcard.c                   |   27 
 hw/milkymist-minimac2.c                  |   45 
 hw/milkymist-pfpu.c                      |   27 
 hw/milkymist-softusb.c                   |   51 
 hw/milkymist-sysctl.c                    |   52 
 hw/milkymist-tmu2.c                      |   27 
 hw/milkymist-uart.c                      |   29 
 hw/milkymist-vgafb.c                     |   39 
 hw/milkymist-vgafb_template.h            |    2 
 hw/mips_fulong2e.c                       |    6 
 hw/mips_jazz.c                           |    6 
 hw/mips_malta.c                          |   34 
 hw/mips_r4k.c                            |    3 
 hw/mipsnet.c                             |   41 
 hw/mpc8544_guts.c                        |   23 
 hw/msi.c                                 |    8 
 hw/msi.h                                 |    2 
 hw/msix.c                                |   12 
 hw/msix.h                                |    2 
 hw/mst_fpga.c                            |   31 
 hw/musicpal.c                            |  190 +-
 hw/nand.c                                |   44 
 hw/ne2000-isa.c                          |   38 
 hw/ne2000.c                              |   45 
 hw/nseries.c                             |    2 
 hw/omap_dss.c                            |    4 
 hw/omap_gpio.c                           |   82 
 hw/omap_intc.c                           |   74 
 hw/onenand.c                             |   43 
 hw/opencores_eth.c                       |   39 
 hw/openpic.c                             |   30 
 hw/openpic.h                             |    2 
 hw/parallel.c                            |   38 
 hw/pc.c                                  |   75 
 hw/pc.h                                  |   38 
 hw/pc_piix.c                             |   93 
 hw/pci.c                                 |  179 -
 hw/pci.h                                 |  102 -
 hw/pci_bridge.c                          |    2 
 hw/pci_ids.h                             |    4 
 hw/pcie.c                                |    2 
 hw/pcie.h                                |   11 
 hw/pckbd.c                               |   27 
 hw/pcnet-pci.c                           |   47 
 hw/pcnet.c                               |    6 
 hw/pcspk.c                               |   84 
 hw/pcspk.h                               |   45 
 hw/pflash_cfi02.c                        |    1 
 hw/piix4.c                               |   42 
 hw/piix_pci.c                            |  145 -
 hw/pl011.c                               |   44 
 hw/pl022.c                               |   21 
 hw/pl031.c                               |   31 
 hw/pl041.c                               |   42 
 hw/pl050.c                               |   46 
 hw/pl061.c                               |   46 
 hw/pl080.c                               |   50 
 hw/pl110.c                               |   73 
 hw/pl181.c                               |   29 
 hw/pl190.c                               |   29 
 hw/ppc440.c                              |  106 -
 hw/ppc440.h                              |   21 
 hw/ppc440_bamboo.c                       |  154 +
 hw/ppc4xx_pci.c                          |  148 -
 hw/ppc_newworld.c                        |    2 
 hw/ppc_prep.c                            |   82 
 hw/ppce500_pci.c                         |   51 
 hw/ppce500_spin.c                        |   23 
 hw/prep_pci.c                            |  184 +
 hw/prep_pci.h                            |   11 
 hw/primecell.h                           |    6 
 hw/ptimer.c                              |    1 
 hw/ptimer.h                              |   39 
 hw/pxa2xx.c                              |  112 -
 hw/pxa2xx_dma.c                          |   38 
 hw/pxa2xx_gpio.c                         |   38 
 hw/pxa2xx_keypad.c                       |   75 
 hw/pxa2xx_lcd.c                          |   67 
 hw/pxa2xx_mmci.c                         |    3 
 hw/pxa2xx_pcmcia.c                       |    3 
 hw/pxa2xx_pic.c                          |   28 
 hw/pxa2xx_timer.c                        |   79 
 hw/qdev-addr.c                           |   13 
 hw/qdev-monitor.c                        |  594 ++++++
 hw/qdev-properties.c                     |  560 +++--
 hw/qdev.c                                | 1119 +----------
 hw/qdev.h                                |  396 ----
 hw/qxl.c                                 |   81 
 hw/realview.c                            |   36 
 hw/realview_gic.c                        |   28 
 hw/rtl8139.c                             |   51 
 hw/s390-virtio-bus.c                     |  163 +
 hw/s390-virtio-bus.h                     |   19 
 hw/s390-virtio.c                         |    1 
 hw/sb16.c                                |  145 -
 hw/sbi.c                                 |   27 
 hw/scsi-bus.c                            |  104 -
 hw/scsi-disk.c                           |  190 +-
 hw/scsi-generic.c                        |   46 
 hw/scsi.h                                |   30 
 hw/serial.c                              |   40 
 hw/sga.c                                 |   25 
 hw/sh_pci.c                              |   45 
 hw/sh_timer.c                            |    1 
 hw/slavio_intctl.c                       |   27 
 hw/slavio_misc.c                         |   45 
 hw/slavio_timer.c                        |   38 
 hw/sm501.c                               |   11 
 hw/smbios.c                              |    2 
 hw/smbus.c                               |   85 
 hw/smbus.h                               |   40 
 hw/smbus_eeprom.c                        |   43 
 hw/smc91c111.c                           |   39 
 hw/spapr.c                               |  136 -
 hw/spapr_hcall.c                         |    5 
 hw/spapr_llan.c                          |   48 
 hw/spapr_pci.c                           |  212 --
 hw/spapr_rtas.c                          |    5 
 hw/spapr_vio.c                           |   89 
 hw/spapr_vio.h                           |   34 
 hw/spapr_vscsi.c                         |   44 
 hw/spapr_vty.c                           |   44 
 hw/sparc32_dma.c                         |   39 
 hw/spitz.c                               |  117 -
 hw/ssd0303.c                             |   41 
 hw/ssd0323.c                             |   24 
 hw/ssi-sd.c                              |   27 
 hw/ssi.c                                 |   42 
 hw/ssi.h                                 |   18 
 hw/stellaris.c                           |   75 
 hw/stellaris_enet.c                      |   35 
 hw/strongarm.c                           |  156 +
 hw/sun4c_intctl.c                        |   27 
 hw/sun4m.c                               |   97 -
 hw/sun4m_iommu.c                         |   37 
 hw/sun4u.c                               |   85 
 hw/sysbus.c                              |   50 
 hw/sysbus.h                              |   25 
 hw/tc6393xb.c                            |    3 
 hw/tcx.c                                 |   78 
 hw/tmp105.c                              |   45 
 hw/tosa.c                                |   61 
 hw/tusb6010.c                            |   25 
 hw/twl92230.c                            |   64 
 hw/unin_pci.c                            |  224 +-
 hw/usb-audio.c                           |  714 +++++++
 hw/usb-bt.c                              |   65 
 hw/usb-bus.c                             |  196 +-
 hw/usb-ccid.c                            |  152 +
 hw/usb-desc.c                            |  161 +
 hw/usb-desc.h                            |    5 
 hw/usb-ehci.c                            |  164 -
 hw/usb-hid.c                             |  133 -
 hw/usb-hub.c                             |  119 -
 hw/usb-msd.c                             |   72 
 hw/usb-musb.c                            |   17 
 hw/usb-net.c                             |   76 
 hw/usb-ohci.c                            |  162 -
 hw/usb-serial.c                          |  108 -
 hw/usb-uhci.c                            |  298 +--
 hw/usb-wacom.c                           |   52 
 hw/usb-xhci.c                            | 2934 +++++++++++++++++++++++++++++++
 hw/usb.c                                 |  371 ++-
 hw/usb.h                                 |  157 +
 hw/versatile_pci.c                       |   62 
 hw/versatilepb.c                         |   30 
 hw/vexpress.c                            |  412 +++-
 hw/vga-isa.c                             |   27 
 hw/vga-pci.c                             |   36 
 hw/vga.c                                 |  398 ++--
 hw/vga.h                                 |  159 +
 hw/vga_int.h                             |   16 
 hw/vga_template.h                        |   74 
 hw/vhost.c                               |    5 
 hw/vhost_net.c                           |    3 
 hw/virtex_ml507.c                        |    1 
 hw/virtio-blk.c                          |    8 
 hw/virtio-console.c                      |   94 
 hw/virtio-net.c                          |    2 
 hw/virtio-pci.c                          |  248 +-
 hw/virtio-serial-bus.c                   |   80 
 hw/virtio-serial.h                       |   85 
 hw/virtio.c                              |   15 
 hw/vmmouse.c                             |   41 
 hw/vmport.c                              |   25 
 hw/vmware_vga.c                          |   43 
 hw/vmware_vga.h                          |    8 
 hw/vt82c686.c                            |  146 -
 hw/wdt_i6300esb.c                        |   41 
 hw/wdt_ib700.c                           |   26 
 hw/wm8750.c                              |   45 
 hw/xen_backend.c                         |    3 
 hw/xen_disk.c                            |    3 
 hw/xen_nic.c                             |    3 
 hw/xen_platform.c                        |   42 
 hw/xgmac.c                               |  433 ++++
 hw/xilinx_axidma.c                       |   36 
 hw/xilinx_axienet.c                      |   44 
 hw/xilinx_ethlite.c                      |   39 
 hw/xilinx_intc.c                         |   33 
 hw/xilinx_timer.c                        |   36 
 hw/xilinx_uartlite.c                     |   23 
 hw/xio3130_downstream.c                  |   67 
 hw/xio3130_upstream.c                    |   61 
 hw/z2.c                                  |   63 
 hw/zaurus.c                              |   36 
 include/qemu/object.h                    |  855 +++++++++
 include/qemu/qom-qobject.h               |   42 
 input.c                                  |    8 
 iov.c                                    |    3 
 json-lexer.c                             |    1 
 kvm-all.c                                |  179 +
 kvm-stub.c                               |   10 
 kvm.h                                    |   22 
 libcacard/Makefile                       |    2 
 linux-headers/asm-powerpc/kvm.h          |   11 
 linux-headers/asm-powerpc/kvm_para.h     |   41 
 linux-headers/asm-s390/kvm.h             |    9 
 linux-headers/asm-x86/hyperv.h           |    1 
 linux-headers/asm-x86/kvm.h              |    4 
 linux-headers/linux/kvm.h                |   78 
 linux-headers/linux/kvm_para.h           |    1 
 linux-headers/linux/virtio_ring.h        |    6 
 linux-user/elfload.c                     |   15 
 linux-user/main.c                        |    7 
 linux-user/mips64/syscall.h              |    3 
 linux-user/mipsn32/syscall.h             |    3 
 linux-user/qemu.h                        |    3 
 linux-user/signal.c                      |    8 
 linux-user/strace.c                      |   19 
 linux-user/syscall.c                     |  328 +++
 linux-user/syscall_defs.h                |    6 
 main-loop.c                              |    7 
 main-loop.h                              |   12 
 memory.c                                 |   62 
 memory.h                                 |   40 
 migration-exec.c                         |    2 
 migration-fd.c                           |    2 
 migration-tcp.c                          |    2 
 migration-unix.c                         |    2 
 migration.c                              |    4 
 module.c                                 |    2 
 module.h                                 |    4 
 monitor.c                                |  192 --
 monitor.h                                |    7 
 net.c                                    |   36 
 net.h                                    |   16 
 net/checksum.c                           |    2 
 net/socket.c                             |    8 
 net/tap.c                                |  204 ++
 net/tap.h                                |    3 
 notify.c                                 |   12 
 notify.h                                 |    8 
 os-posix.c                               |    2 
 pc-bios/README                           |    2 
 pc-bios/bamboo.dtb                       |binary
 pc-bios/bamboo.dts                       |  128 -
 pc-bios/bios.bin                         |binary
 pc-bios/optionrom/Makefile               |    3 
 pc-bios/slof.bin                         |binary
 pflib.c                                  |    2 
 posix-aio-compat.c                       |    2 
 qapi-schema.json                         |  333 +++
 qemu-bridge-helper.c                     |  410 ++++
 qemu-char.c                              |   10 
 qemu-char.h                              |    2 
 qemu-common.h                            |   10 
 qemu-config.c                            |   36 
 qemu-coroutine-int.h                     |    2 
 qemu-coroutine-sleep.c                   |   38 
 qemu-coroutine.h                         |    9 
 qemu-doc.texi                            |   54 
 qemu-file.h                              |  238 ++
 qemu-ga.c                                |    2 
 qemu-img.c                               |   46 
 qemu-io.c                                |  129 +
 qemu-nbd.c                               |   42 
 qemu-option.c                            |   69 
 qemu-option.h                            |    3 
 qemu-options.hx                          |  128 +
 qemu-queue.h                             |  192 --
 qemu-thread-win32.c                      |    9 
 qemu-timer.c                             |   31 
 qemu-timer.h                             |   13 
 qemu-tool.c                              |    9 
 qerror.c                                 |  113 -
 qerror.h                                 |   90 
 qmp-commands.hx                          |   60 
 qmp.c                                    |  225 ++
 qom/Makefile                             |    1 
 qom/container.c                          |   27 
 qom/object.c                             | 1138 ++++++++++++
 qom/qom-qobject.c                        |   44 
 roms/SLOF                                |    2 
 roms/seabios                             |    2 
 scripts/check-qerror.sh                  |   22 
 slirp/ip_icmp.c                          |    5 
 slirp/misc.c                             |   67 
 sysemu.h                                 |    2 
 target-arm/cpu.h                         |    5 
 target-arm/helper.c                      |  102 -
 target-arm/machine.c                     |    2 
 target-arm/translate.c                   |    8 
 target-i386/cpuid.c                      |   14 
 target-i386/hyperv.c                     |   64 
 target-i386/hyperv.h                     |   45 
 target-i386/kvm.c                        |  127 +
 target-i386/translate.c                  |    3 
 target-ppc/cpu.h                         |   59 
 target-ppc/helper.c                      |   35 
 target-ppc/helper.h                      |    5 
 target-ppc/kvm.c                         |   10 
 target-ppc/op_helper.c                   |  159 +
 target-ppc/translate.c                   |   75 
 target-ppc/translate_init.c              |   64 
 target-sparc/vis_helper.c                |    2 
 tcg/arm/tcg-target.c                     |    2 
 test-qmp-input-visitor.c                 |    7 
 tests/Makefile                           |    2 
 tests/tcg/cris/Makefile                  |   10 
 trace-events                             |   20 
 ui/sdl.c                                 |   60 
 ui/spice-core.c                          |    5 
 ui/vnc.c                                 |  157 +
 ui/vnc.h                                 |   16 
 usb-bsd.c                                |   36 
 usb-linux.c                              |  554 +----
 usb-redir.c                              |  284 ++-
 vl.c                                     |  144 +
 vmstate.h                                |  618 ++++++
 xen-all.c                                |    5 
 xen-mapcache.c                           |    2 
 xen-stub.c                               |    2 
 547 files changed, 35198 insertions(+), 11395 deletions(-)

New commits:
commit 99c7f87826337fa81f2f0f9baa9ca0a44faf90e9
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Feb 15 09:15:37 2012 +0100

    input: send kbd+mouse events only to running guests.
    
    Trying to interact with a stopped guest will queue up the events,
    then send them all at once when the guest continues running, with
    a high chance to have them cause unwanted actions.
    
    Avoid that by only injecting the input events only when the guest
    is in running state.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/input.c b/input.c
index b618ea4..6b5c2c3 100644
--- a/input.c
+++ b/input.c
@@ -130,6 +130,9 @@ void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry)
 
 void kbd_put_keycode(int keycode)
 {
+    if (!runstate_is_running()) {
+        return;
+    }
     if (qemu_put_kbd_event) {
         qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycode);
     }
@@ -151,6 +154,9 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
     void *mouse_event_opaque;
     int width, height;
 
+    if (!runstate_is_running()) {
+        return;
+    }
     if (QTAILQ_EMPTY(&mouse_handlers)) {
         return;
     }
commit aa24822bdc7c4e74afbc6fa1324b01cf067da7cb
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Jan 24 16:29:29 2012 +0100

    i8259: Do not clear level-triggered lines in IRR on init
    
    When an input line is handled as level-triggered, it will immediately
    raise an IRQ on the output of a PIC again that goes through an init
    reset. So only clear the edge-triggered inputs from IRR in that
    scenario.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/i8259.c b/hw/i8259.c
index 1a4b1ab..53daf78 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -231,8 +231,8 @@ static void pic_reset(DeviceState *dev)
 {
     PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, dev);
 
-    pic_init_reset(s);
     s->elcr = 0;
+    pic_init_reset(s);
 }
 
 static void pic_ioport_write(void *opaque, target_phys_addr_t addr64,
diff --git a/hw/i8259_common.c b/hw/i8259_common.c
index 775fda4..ab3d98b 100644
--- a/hw/i8259_common.c
+++ b/hw/i8259_common.c
@@ -28,7 +28,7 @@
 void pic_reset_common(PICCommonState *s)
 {
     s->last_irr = 0;
-    s->irr = 0;
+    s->irr &= s->elcr;
     s->imr = 0;
     s->isr = 0;
     s->priority_add = 0;
diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c
index eb98889..94d1b9a 100644
--- a/hw/kvm/i8259.c
+++ b/hw/kvm/i8259.c
@@ -84,8 +84,8 @@ static void kvm_pic_reset(DeviceState *dev)
 {
     PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, dev);
 
-    pic_reset_common(s);
     s->elcr = 0;
+    pic_reset_common(s);
 
     kvm_pic_put(s);
 }
commit 4aa5d2853a69d95f5e05bd02200dfc6f47cab9de
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Wed Feb 1 20:31:43 2012 +0100

    i8254: Factor out pit_get_channel_info
    
    Instead of providing 4 individual query functions for mode, gate, output
    and initial counter state, introduce a service that queries all
    information at once. This comes with tiny additional costs for
    pcspk_callback but with a much cleaner interface. Also, it will simplify
    the implementation of the KVM in-kernel PIT model.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/i8254.c b/hw/i8254.c
index 3d39630..f30396a 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -90,7 +90,7 @@ static int pit_get_count(PITChannelState *s)
 }
 
 /* get pit output bit */
-static int pit_get_out1(PITChannelState *s, int64_t current_time)
+static int pit_get_out(PITChannelState *s, int64_t current_time)
 {
     uint64_t d;
     int out;
@@ -122,13 +122,6 @@ static int pit_get_out1(PITChannelState *s, int64_t current_time)
     return out;
 }
 
-int pit_get_out(ISADevice *dev, int channel, int64_t current_time)
-{
-    PITState *pit = DO_UPCAST(PITState, dev, dev);
-    PITChannelState *s = &pit->channels[channel];
-    return pit_get_out1(s, current_time);
-}
-
 /* return -1 if no transition will occur.  */
 static int64_t pit_get_next_transition_time(PITChannelState *s,
                                             int64_t current_time)
@@ -215,25 +208,15 @@ void pit_set_gate(ISADevice *dev, int channel, int val)
     s->gate = val;
 }
 
-int pit_get_gate(ISADevice *dev, int channel)
-{
-    PITState *pit = DO_UPCAST(PITState, dev, dev);
-    PITChannelState *s = &pit->channels[channel];
-    return s->gate;
-}
-
-int pit_get_initial_count(ISADevice *dev, int channel)
+void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info)
 {
     PITState *pit = DO_UPCAST(PITState, dev, dev);
     PITChannelState *s = &pit->channels[channel];
-    return s->count;
-}
 
-int pit_get_mode(ISADevice *dev, int channel)
-{
-    PITState *pit = DO_UPCAST(PITState, dev, dev);
-    PITChannelState *s = &pit->channels[channel];
-    return s->mode;
+    info->gate = s->gate;
+    info->mode = s->mode;
+    info->initial_count = s->count;
+    info->out = pit_get_out(s, qemu_get_clock_ns(vm_clock));
 }
 
 static inline void pit_load_count(PITChannelState *s, int val)
@@ -274,7 +257,9 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
                     if (!(val & 0x10) && !s->status_latched) {
                         /* status latch */
                         /* XXX: add BCD and null count */
-                        s->status =  (pit_get_out1(s, qemu_get_clock_ns(vm_clock)) << 7) |
+                        s->status =
+                            (pit_get_out(s,
+                                         qemu_get_clock_ns(vm_clock)) << 7) |
                             (s->rw_mode << 4) |
                             (s->mode << 1) |
                             s->bcd;
@@ -381,7 +366,7 @@ static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
         return;
     }
     expire_time = pit_get_next_transition_time(s, current_time);
-    irq_level = pit_get_out1(s, current_time);
+    irq_level = pit_get_out(s, current_time);
     qemu_set_irq(s->irq, irq_level);
 #ifdef DEBUG_PIT
     printf("irq_level=%d next_delay=%f\n",
diff --git a/hw/i8254.h b/hw/i8254.h
index 8ad8e07..a1d2e98 100644
--- a/hw/i8254.h
+++ b/hw/i8254.h
@@ -30,6 +30,13 @@
 
 #define PIT_FREQ 1193182
 
+typedef struct PITChannelInfo {
+    int gate;
+    int mode;
+    int initial_count;
+    int out;
+} PITChannelInfo;
+
 static inline ISADevice *pit_init(ISABus *bus, int base, int isa_irq,
                                   qemu_irq alt_irq)
 {
@@ -45,9 +52,6 @@ static inline ISADevice *pit_init(ISABus *bus, int base, int isa_irq,
 }
 
 void pit_set_gate(ISADevice *dev, int channel, int val);
-int pit_get_gate(ISADevice *dev, int channel);
-int pit_get_initial_count(ISADevice *dev, int channel);
-int pit_get_mode(ISADevice *dev, int channel);
-int pit_get_out(ISADevice *dev, int channel, int64_t current_time);
+void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info);
 
 #endif /* !HW_I8254_H */
diff --git a/hw/pcspk.c b/hw/pcspk.c
index 49dd969..e430324 100644
--- a/hw/pcspk.c
+++ b/hw/pcspk.c
@@ -75,12 +75,16 @@ static inline void generate_samples(PCSpkState *s)
 static void pcspk_callback(void *opaque, int free)
 {
     PCSpkState *s = opaque;
+    PITChannelInfo ch;
     unsigned int n;
 
-    if (pit_get_mode(s->pit, 2) != 3)
+    pit_get_channel_info(s->pit, 2, &ch);
+
+    if (ch.mode != 3) {
         return;
+    }
 
-    n = pit_get_initial_count(s->pit, 2);
+    n = ch.initial_count;
     /* avoid frequencies that are not reproducible with sample rate */
     if (n < PCSPK_MIN_COUNT)
         n = 0;
@@ -121,12 +125,14 @@ static uint64_t pcspk_io_read(void *opaque, target_phys_addr_t addr,
                               unsigned size)
 {
     PCSpkState *s = opaque;
-    int out;
+    PITChannelInfo ch;
+
+    pit_get_channel_info(s->pit, 2, &ch);
 
     s->dummy_refresh_clock ^= (1 << 4);
-    out = pit_get_out(s->pit, 2, qemu_get_clock_ns(vm_clock)) << 5;
 
-    return pit_get_gate(s->pit, 2) | (s->data_on << 1) | s->dummy_refresh_clock | out;
+    return ch.gate | (s->data_on << 1) | s->dummy_refresh_clock |
+       (ch.out << 5);
 }
 
 static void pcspk_io_write(void *opaque, target_phys_addr_t addr, uint64_t val,
commit 302fe51b5900c5ca5be921269b61f4862e0634ce
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Fri Feb 17 11:24:34 2012 +0100

    pcspk: Convert to qdev
    
    Convert the PC speaker device to a qdev ISA model. Move the public
    interface to a dedicated header file at this chance.
    
    CC: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/arch_init.c b/arch_init.c
index 699bdd1..a95ef49 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -42,6 +42,7 @@
 #include "gdbstub.h"
 #include "hw/smbios.h"
 #include "exec-memory.h"
+#include "hw/pcspk.h"
 
 #ifdef TARGET_SPARC
 int graphic_width = 1024;
diff --git a/hw/i82378.c b/hw/i82378.c
index cc41564..faad1a3 100644
--- a/hw/i82378.c
+++ b/hw/i82378.c
@@ -20,6 +20,7 @@
 #include "pci.h"
 #include "pc.h"
 #include "i8254.h"
+#include "pcspk.h"
 
 //#define DEBUG_I82378
 
@@ -195,7 +196,7 @@ static void i82378_init(DeviceState *dev, I82378State *s)
     pit = pit_init(isabus, 0x40, 0, NULL);
 
     /* speaker */
-    pcspk_init(pit);
+    pcspk_init(isabus, pit);
 
     /* 2 82C37 (dma) */
     DMA_init(1, &s->out[1]);
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index b61b218..65608dc 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -37,6 +37,7 @@
 #include "loader.h"
 #include "mc146818rtc.h"
 #include "i8254.h"
+#include "pcspk.h"
 #include "blockdev.h"
 #include "sysbus.h"
 #include "exec-memory.h"
@@ -193,7 +194,7 @@ static void mips_jazz_init(MemoryRegion *address_space,
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     DMA_init(0, cpu_exit_irq);
     pit = pit_init(isa_bus, 0x40, 0, NULL);
-    pcspk_init(pit);
+    pcspk_init(isa_bus, pit);
 
     /* ISA IO space at 0x90000000 */
     isa_mmio_init(0x90000000, 0x01000000);
diff --git a/hw/pc.c b/hw/pc.c
index 8e26563..5746129 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -37,6 +37,7 @@
 #include "multiboot.h"
 #include "mc146818rtc.h"
 #include "i8254.h"
+#include "pcspk.h"
 #include "msi.h"
 #include "sysbus.h"
 #include "sysemu.h"
@@ -1172,7 +1173,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
         /* connect PIT to output control line of the HPET */
         qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0));
     }
-    pcspk_init(pit);
+    pcspk_init(isa_bus, pit);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
diff --git a/hw/pc.h b/hw/pc.h
index b08708d..1b47bbd 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -149,10 +149,6 @@ void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
 /* hpet.c */
 extern int no_hpet;
 
-/* pcspk.c */
-void pcspk_init(ISADevice *pit);
-int pcspk_audio_init(ISABus *bus);
-
 /* piix_pci.c */
 struct PCII440FXState;
 typedef struct PCII440FXState PCII440FXState;
diff --git a/hw/pcspk.c b/hw/pcspk.c
index 43df818..49dd969 100644
--- a/hw/pcspk.c
+++ b/hw/pcspk.c
@@ -28,6 +28,7 @@
 #include "audio/audio.h"
 #include "qemu-timer.h"
 #include "i8254.h"
+#include "pcspk.h"
 
 #define PCSPK_BUF_LEN 1792
 #define PCSPK_SAMPLE_RATE 32000
@@ -35,10 +36,13 @@
 #define PCSPK_MIN_COUNT ((PIT_FREQ + PCSPK_MAX_FREQ - 1) / PCSPK_MAX_FREQ)
 
 typedef struct {
+    ISADevice dev;
+    MemoryRegion ioport;
+    uint32_t iobase;
     uint8_t sample_buf[PCSPK_BUF_LEN];
     QEMUSoundCard card;
     SWVoiceOut *voice;
-    ISADevice *pit;
+    void *pit;
     unsigned int pit_count;
     unsigned int samples;
     unsigned int play_pos;
@@ -47,7 +51,7 @@ typedef struct {
 } PCSpkState;
 
 static const char *s_spk = "pcspk";
-static PCSpkState pcspk_state;
+static PCSpkState *pcspk_state;
 
 static inline void generate_samples(PCSpkState *s)
 {
@@ -99,7 +103,7 @@ static void pcspk_callback(void *opaque, int free)
 
 int pcspk_audio_init(ISABus *bus)
 {
-    PCSpkState *s = &pcspk_state;
+    PCSpkState *s = pcspk_state;
     struct audsettings as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0};
 
     AUD_register_card(s_spk, &s->card);
@@ -113,7 +117,8 @@ int pcspk_audio_init(ISABus *bus)
     return 0;
 }
 
-static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr)
+static uint64_t pcspk_io_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     PCSpkState *s = opaque;
     int out;
@@ -124,7 +129,8 @@ static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr)
     return pit_get_gate(s->pit, 2) | (s->data_on << 1) | s->dummy_refresh_clock | out;
 }
 
-static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void pcspk_io_write(void *opaque, target_phys_addr_t addr, uint64_t val,
+                           unsigned size)
 {
     PCSpkState *s = opaque;
     const int gate = val & 1;
@@ -138,11 +144,52 @@ static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
-void pcspk_init(ISADevice *pit)
+static const MemoryRegionOps pcspk_io_ops = {
+    .read = pcspk_io_read,
+    .write = pcspk_io_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static int pcspk_initfn(ISADevice *dev)
 {
-    PCSpkState *s = &pcspk_state;
+    PCSpkState *s = DO_UPCAST(PCSpkState, dev, dev);
+
+    memory_region_init_io(&s->ioport, &pcspk_io_ops, s, "elcr", 1);
+    isa_register_ioport(dev, &s->ioport, s->iobase);
+
+    pcspk_state = s;
+
+    return 0;
+}
+
+static Property pcspk_properties[] = {
+    DEFINE_PROP_HEX32("iobase", PCSpkState, iobase,  -1),
+    DEFINE_PROP_PTR("pit", PCSpkState, pit),
+    DEFINE_PROP_END_OF_LIST(),
+};
 
-    s->pit = pit;
-    register_ioport_read(0x61, 1, 1, pcspk_ioport_read, s);
-    register_ioport_write(0x61, 1, 1, pcspk_ioport_write, s);
+static void pcspk_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+
+    ic->init = pcspk_initfn;
+    dc->no_user = 1;
+    dc->props = pcspk_properties;
+}
+
+static TypeInfo pcspk_info = {
+    .name           = "isa-pcspk",
+    .parent         = TYPE_ISA_DEVICE,
+    .instance_size  = sizeof(PCSpkState),
+    .class_init     = pcspk_class_initfn,
+};
+
+static void pcspk_register(void)
+{
+    type_register_static(&pcspk_info);
 }
+type_init(pcspk_register)
diff --git a/hw/pcspk.h b/hw/pcspk.h
new file mode 100644
index 0000000..7f42bac
--- /dev/null
+++ b/hw/pcspk.h
@@ -0,0 +1,45 @@
+/*
+ * QEMU PC speaker emulation
+ *
+ * Copyright (c) 2006 Joachim Henke
+ *
+ * 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 HW_PCSPK_H
+#define HW_PCSPK_H
+
+#include "hw.h"
+#include "isa.h"
+
+static inline ISADevice *pcspk_init(ISABus *bus, ISADevice *pit)
+{
+    ISADevice *dev;
+
+    dev = isa_create(bus, "isa-pcspk");
+    qdev_prop_set_uint32(&dev->qdev, "iobase", 0x61);
+    qdev_prop_set_ptr(&dev->qdev, "pit", pit);
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
+
+int pcspk_audio_init(ISABus *bus);
+
+#endif /* !HW_PCSPK_H */
commit ce967e2f33861b0e17753f97fa4527b5943c94b6
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Wed Feb 1 20:31:41 2012 +0100

    i8254: Rework & fix interaction with HPET in legacy mode
    
    When the HPET enters legacy mode, the IRQ output of the PIT is
    suppressed and replaced by the HPET timer 0. But the current code to
    emulate this was broken in many ways. It reset the PIT state after
    re-enabling, it worked against a stale static PIT structure, and it did
    not properly saved/restored the IRQ output mask in the PIT vmstate.
    
    This patch solves the PIT IRQ control in a different way. On x86, it
    both redirects the PIT IRQ to the HPET, just like the RTC. But it also
    keeps the control line from the HPET to the PIT. This allows to disable
    the PIT QEMU timer when it is not needed. The PIT's view on the control
    line state is now saved in the same format that qemu-kvm is already
    using.
    
    Note that, in contrast to the suppressed RTC IRQ line, we do not need to
    save/restore the PIT line state in the HPET. As we trigger a PIT IRQ
    update via the control line, the line state is reconstructed on mode
    switch.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/hpet.c b/hw/hpet.c
index 16833fa..fd3ddca 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -65,6 +65,7 @@ typedef struct HPETState {
     qemu_irq irqs[HPET_NUM_IRQ_ROUTES];
     uint32_t flags;
     uint8_t rtc_irq_level;
+    qemu_irq pit_enabled;
     uint8_t num_timers;
     HPETTimer timer[HPET_MAX_TIMERS];
 
@@ -573,12 +574,15 @@ static void hpet_ram_write(void *opaque, target_phys_addr_t addr,
                     hpet_del_timer(&s->timer[i]);
                 }
             }
-            /* i8254 and RTC are disabled when HPET is in legacy mode */
+            /* i8254 and RTC output pins are disabled
+             * when HPET is in legacy mode */
             if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
-                hpet_pit_disable();
+                qemu_set_irq(s->pit_enabled, 0);
+                qemu_irq_lower(s->irqs[0]);
                 qemu_irq_lower(s->irqs[RTC_ISA_IRQ]);
             } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
-                hpet_pit_enable();
+                qemu_irq_lower(s->irqs[0]);
+                qemu_set_irq(s->pit_enabled, 1);
                 qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level);
             }
             break;
@@ -632,7 +636,6 @@ static void hpet_reset(DeviceState *d)
 {
     HPETState *s = FROM_SYSBUS(HPETState, sysbus_from_qdev(d));
     int i;
-    static int count = 0;
 
     for (i = 0; i < s->num_timers; i++) {
         HPETTimer *timer = &s->timer[i];
@@ -649,32 +652,30 @@ static void hpet_reset(DeviceState *d)
         timer->wrap_flag = 0;
     }
 
+    qemu_set_irq(s->pit_enabled, 1);
     s->hpet_counter = 0ULL;
     s->hpet_offset = 0ULL;
     s->config = 0ULL;
-    if (count > 0) {
-        /* we don't enable pit when hpet_reset is first called (by hpet_init)
-         * because hpet is taking over for pit here. On subsequent invocations,
-         * hpet_reset is called due to system reset. At this point control must
-         * be returned to pit until SW reenables hpet.
-         */
-        hpet_pit_enable();
-    }
     hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
     hpet_cfg.hpet[s->hpet_id].address = sysbus_from_qdev(d)->mmio[0].addr;
-    count = 1;
 
     /* to document that the RTC lowers its output on reset as well */
     s->rtc_irq_level = 0;
 }
 
-static void hpet_handle_rtc_irq(void *opaque, int n, int level)
+static void hpet_handle_legacy_irq(void *opaque, int n, int level)
 {
     HPETState *s = FROM_SYSBUS(HPETState, opaque);
 
-    s->rtc_irq_level = level;
-    if (!hpet_in_legacy_mode(s)) {
-        qemu_set_irq(s->irqs[RTC_ISA_IRQ], level);
+    if (n == HPET_LEGACY_PIT_INT) {
+        if (!hpet_in_legacy_mode(s)) {
+            qemu_set_irq(s->irqs[0], level);
+        }
+    } else {
+        s->rtc_irq_level = level;
+        if (!hpet_in_legacy_mode(s)) {
+            qemu_set_irq(s->irqs[RTC_ISA_IRQ], level);
+        }
     }
 }
 
@@ -717,7 +718,8 @@ static int hpet_init(SysBusDevice *dev)
     s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
     s->capability |= ((HPET_CLK_PERIOD) << 32);
 
-    qdev_init_gpio_in(&dev->qdev, hpet_handle_rtc_irq, 1);
+    qdev_init_gpio_in(&dev->qdev, hpet_handle_legacy_irq, 2);
+    qdev_init_gpio_out(&dev->qdev, &s->pit_enabled, 1);
 
     /* HPET Area */
     memory_region_init_io(&s->iomem, &hpet_ram_ops, s, "hpet", 0x400);
diff --git a/hw/hpet_emul.h b/hw/hpet_emul.h
index 6128702..757f79f 100644
--- a/hw/hpet_emul.h
+++ b/hw/hpet_emul.h
@@ -22,6 +22,9 @@
 
 #define HPET_NUM_IRQ_ROUTES     32
 
+#define HPET_LEGACY_PIT_INT     0
+#define HPET_LEGACY_RTC_INT     1
+
 #define HPET_CFG_ENABLE 0x001
 #define HPET_CFG_LEGACY 0x002
 
diff --git a/hw/i8254.c b/hw/i8254.c
index aa7e9fc..3d39630 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -52,6 +52,7 @@ typedef struct PITChannelState {
     int64_t next_transition_time;
     QEMUTimer *irq_timer;
     qemu_irq irq;
+    uint32_t irq_disabled;
 } PITChannelState;
 
 typedef struct PITState {
@@ -61,8 +62,6 @@ typedef struct PITState {
     PITChannelState channels[3];
 } PITState;
 
-static PITState pit_state;
-
 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
 
 static int pit_get_count(PITChannelState *s)
@@ -378,8 +377,9 @@ static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
     int64_t expire_time;
     int irq_level;
 
-    if (!s->irq_timer)
+    if (!s->irq_timer || s->irq_disabled) {
         return;
+    }
     expire_time = pit_get_next_transition_time(s, current_time);
     irq_level = pit_get_out1(s, current_time);
     qemu_set_irq(s->irq, irq_level);
@@ -450,6 +450,7 @@ static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
         qemu_get_8s(f, &s->bcd);
         qemu_get_8s(f, &s->gate);
         s->count_load_time=qemu_get_be64(f);
+        s->irq_disabled = 0;
         if (s->irq_timer) {
             s->next_transition_time=qemu_get_be64(f);
             qemu_get_timer(f, s->irq_timer);
@@ -460,11 +461,12 @@ static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
 
 static const VMStateDescription vmstate_pit = {
     .name = "i8254",
-    .version_id = 2,
+    .version_id = 3,
     .minimum_version_id = 2,
     .minimum_version_id_old = 1,
     .load_state_old = pit_load_old,
     .fields      = (VMStateField []) {
+        VMSTATE_UINT32_V(channels[0].irq_disabled, PITState, 3),
         VMSTATE_STRUCT_ARRAY(channels, PITState, 3, 2, vmstate_pit_channel, PITChannelState),
         VMSTATE_TIMER(channels[0].irq_timer, PITState),
         VMSTATE_END_OF_LIST()
@@ -483,7 +485,7 @@ static void pit_reset(DeviceState *dev)
         s->gate = (i != 2);
         s->count_load_time = qemu_get_clock_ns(vm_clock);
         s->count = 0x10000;
-        if (i == 0) {
+        if (i == 0 && !s->irq_disabled) {
             s->next_transition_time =
                 pit_get_next_transition_time(s, s->count_load_time);
             qemu_mod_timer(s->irq_timer, s->next_transition_time);
@@ -491,26 +493,20 @@ static void pit_reset(DeviceState *dev)
     }
 }
 
-/* When HPET is operating in legacy mode, i8254 timer0 is disabled */
-void hpet_pit_disable(void) {
-    PITChannelState *s;
-    s = &pit_state.channels[0];
-    if (s->irq_timer)
-        qemu_del_timer(s->irq_timer);
-}
-
-/* When HPET is reset or leaving legacy mode, it must reenable i8254
- * timer 0
- */
-
-void hpet_pit_enable(void)
+/* When HPET is operating in legacy mode, suppress the ignored timer IRQ,
+ * reenable it when legacy mode is left again. */
+static void pit_irq_control(void *opaque, int n, int enable)
 {
-    PITState *pit = &pit_state;
-    PITChannelState *s;
-    s = &pit->channels[0];
-    s->mode = 3;
-    s->gate = 1;
-    pit_load_count(s, 0);
+    PITState *pit = opaque;
+    PITChannelState *s = &pit->channels[0];
+
+    if (enable) {
+        s->irq_disabled = 0;
+        pit_irq_timer_update(s, qemu_get_clock_ns(vm_clock));
+    } else {
+        s->irq_disabled = 1;
+        qemu_del_timer(s->irq_timer);
+    }
 }
 
 static const MemoryRegionPortio pit_portio[] = {
@@ -536,6 +532,8 @@ static int pit_initfn(ISADevice *dev)
     memory_region_init_io(&pit->ioports, &pit_ioport_ops, pit, "pit", 4);
     isa_register_ioport(dev, &pit->ioports, pit->iobase);
 
+    qdev_init_gpio_in(&dev->qdev, pit_irq_control, 1);
+
     qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
 
     return 0;
diff --git a/hw/i8254.h b/hw/i8254.h
index fc64a63..8ad8e07 100644
--- a/hw/i8254.h
+++ b/hw/i8254.h
@@ -50,7 +50,4 @@ int pit_get_initial_count(ISADevice *dev, int channel);
 int pit_get_mode(ISADevice *dev, int channel);
 int pit_get_out(ISADevice *dev, int channel, int64_t current_time);
 
-void hpet_pit_disable(void);
-void hpet_pit_enable(void);
-
 #endif /* !HW_I8254_H */
diff --git a/hw/pc.c b/hw/pc.c
index ad65a5d..8e26563 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1139,6 +1139,9 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
 {
     int i;
     DriveInfo *fd[MAX_FD];
+    DeviceState *hpet = NULL;
+    int pit_isa_irq = 0;
+    qemu_irq pit_alt_irq = NULL;
     qemu_irq rtc_irq = NULL;
     qemu_irq *a20_line;
     ISADevice *i8042, *port92, *vmmouse, *pit;
@@ -1149,20 +1152,26 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
     register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
 
     if (!no_hpet) {
-        DeviceState *hpet = sysbus_try_create_simple("hpet", HPET_BASE, NULL);
+        hpet = sysbus_try_create_simple("hpet", HPET_BASE, NULL);
 
         if (hpet) {
             for (i = 0; i < GSI_NUM_PINS; i++) {
                 sysbus_connect_irq(sysbus_from_qdev(hpet), i, gsi[i]);
             }
-            rtc_irq = qdev_get_gpio_in(hpet, 0);
+            pit_isa_irq = -1;
+            pit_alt_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_PIT_INT);
+            rtc_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_RTC_INT);
         }
     }
     *rtc_state = rtc_init(isa_bus, 2000, rtc_irq);
 
     qemu_register_boot_set(pc_boot_set, *rtc_state);
 
-    pit = pit_init(isa_bus, 0x40, 0, NULL);
+    pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq);
+    if (hpet) {
+        /* connect PIT to output control line of the HPET */
+        qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0));
+    }
     pcspk_init(pit);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
commit 319ba9f52737fc79de5c2c6abd059933398b72d5
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Wed Feb 1 20:31:40 2012 +0100

    i8254: Pass alternative IRQ output object on initialization
    
    HPET legacy emulation will require control over the PIT IRQ output. To
    enable this, add support for an alternative IRQ output object to the PIT
    factory function. If the isa_irq number is < 0, this object will be
    used.
    
    This also removes the IRQ number property from the PIT class as we now
    use a generic GPIO output pin that is connected by the factory function.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c
index 4c0efd3..ea0fd95 100644
--- a/hw/alpha_dp264.c
+++ b/hw/alpha_dp264.c
@@ -73,7 +73,7 @@ static void clipper_init(ram_addr_t ram_size,
                            clipper_pci_map_irq);
 
     rtc_init(isa_bus, 1980, rtc_irq);
-    pit_init(isa_bus, 0x40, 0);
+    pit_init(isa_bus, 0x40, 0, NULL);
     isa_create_simple(isa_bus, "i8042");
 
     /* VGA setup.  Don't bother loading the bios.  */
diff --git a/hw/i82378.c b/hw/i82378.c
index d3c4ac5..cc41564 100644
--- a/hw/i82378.c
+++ b/hw/i82378.c
@@ -192,7 +192,7 @@ static void i82378_init(DeviceState *dev, I82378State *s)
     isa_bus_irqs(isabus, s->i8259);
 
     /* 1 82C54 (pit) */
-    pit = pit_init(isabus, 0x40, 0);
+    pit = pit_init(isabus, 0x40, 0, NULL);
 
     /* speaker */
     pcspk_init(pit);
diff --git a/hw/i8254.c b/hw/i8254.c
index 71ea849..aa7e9fc 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -57,7 +57,6 @@ typedef struct PITChannelState {
 typedef struct PITState {
     ISADevice dev;
     MemoryRegion ioports;
-    uint32_t irq;
     uint32_t iobase;
     PITChannelState channels[3];
 } PITState;
@@ -532,7 +531,7 @@ static int pit_initfn(ISADevice *dev)
     s = &pit->channels[0];
     /* the timer 0 is connected to an IRQ */
     s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s);
-    s->irq = isa_get_irq(dev, pit->irq);
+    qdev_init_gpio_out(&dev->qdev, &s->irq, 1);
 
     memory_region_init_io(&pit->ioports, &pit_ioport_ops, pit, "pit", 4);
     isa_register_ioport(dev, &pit->ioports, pit->iobase);
@@ -543,7 +542,6 @@ static int pit_initfn(ISADevice *dev)
 }
 
 static Property pit_properties[] = {
-    DEFINE_PROP_UINT32("irq", PITState, irq,  -1),
     DEFINE_PROP_HEX32("iobase", PITState, iobase,  -1),
     DEFINE_PROP_END_OF_LIST(),
 };
diff --git a/hw/i8254.h b/hw/i8254.h
index cd3111c..fc64a63 100644
--- a/hw/i8254.h
+++ b/hw/i8254.h
@@ -30,14 +30,16 @@
 
 #define PIT_FREQ 1193182
 
-static inline ISADevice *pit_init(ISABus *bus, int base, int irq)
+static inline ISADevice *pit_init(ISABus *bus, int base, int isa_irq,
+                                  qemu_irq alt_irq)
 {
     ISADevice *dev;
 
     dev = isa_create(bus, "isa-pit");
     qdev_prop_set_uint32(&dev->qdev, "iobase", base);
-    qdev_prop_set_uint32(&dev->qdev, "irq", irq);
     qdev_init_nofail(&dev->qdev);
+    qdev_connect_gpio_out(&dev->qdev, 0,
+                          isa_irq >= 0 ? isa_get_irq(dev, isa_irq) : alt_irq);
 
     return dev;
 }
diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c
index ead72ae..e3ba9dd 100644
--- a/hw/mips_fulong2e.c
+++ b/hw/mips_fulong2e.c
@@ -364,7 +364,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
     smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd));
 
     /* init other devices */
-    pit = pit_init(isa_bus, 0x40, 0);
+    pit = pit_init(isa_bus, 0x40, 0, NULL);
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     DMA_init(0, cpu_exit_irq);
 
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 61dee4d..b61b218 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -192,7 +192,7 @@ static void mips_jazz_init(MemoryRegion *address_space,
     isa_bus_irqs(isa_bus, i8259);
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     DMA_init(0, cpu_exit_irq);
-    pit = pit_init(isa_bus, 0x40, 0);
+    pit = pit_init(isa_bus, 0x40, 0, NULL);
     pcspk_init(pit);
 
     /* ISA IO space at 0x90000000 */
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 692f79b..86a5fbb 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -970,7 +970,7 @@ void mips_malta_init (ram_addr_t ram_size,
                           isa_get_irq(NULL, 9), NULL, NULL, 0);
     /* TODO: Populate SPD eeprom data.  */
     smbus_eeprom_init(smbus, 8, NULL, 0);
-    pit = pit_init(isa_bus, 0x40, 0);
+    pit = pit_init(isa_bus, 0x40, 0, NULL);
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     DMA_init(0, cpu_exit_irq);
 
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index 1b3ec2d..83401f0 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -270,7 +270,7 @@ void mips_r4k_init (ram_addr_t ram_size,
     isa_mmio_init(0x14000000, 0x00010000);
     isa_mem_base = 0x10000000;
 
-    pit = pit_init(isa_bus, 0x40, 0);
+    pit = pit_init(isa_bus, 0x40, 0, NULL);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
diff --git a/hw/pc.c b/hw/pc.c
index 435fe4d..ad65a5d 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1162,7 +1162,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
 
     qemu_register_boot_set(pc_boot_set, *rtc_state);
 
-    pit = pit_init(isa_bus, 0x40, 0);
+    pit = pit_init(isa_bus, 0x40, 0, NULL);
     pcspk_init(pit);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
commit b1277b03d46b2aeb22f0829aaa1c0f5fe6dd38fe
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Wed Feb 1 20:31:39 2012 +0100

    i8254: Factor out interface header
    
    Move the public interface of the PIT into its own header file and update
    all users.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c
index 876335a..4c0efd3 100644
--- a/hw/alpha_dp264.c
+++ b/hw/alpha_dp264.c
@@ -14,6 +14,7 @@
 #include "sysemu.h"
 #include "mc146818rtc.h"
 #include "ide.h"
+#include "i8254.h"
 
 #define MAX_IDE_BUS 2
 
diff --git a/hw/hpet.c b/hw/hpet.c
index 76769d5..16833fa 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -31,6 +31,7 @@
 #include "hpet_emul.h"
 #include "sysbus.h"
 #include "mc146818rtc.h"
+#include "i8254.h"
 
 //#define HPET_DEBUG
 #ifdef HPET_DEBUG
diff --git a/hw/i82378.c b/hw/i82378.c
index 3929c04..d3c4ac5 100644
--- a/hw/i82378.c
+++ b/hw/i82378.c
@@ -19,6 +19,7 @@
 
 #include "pci.h"
 #include "pc.h"
+#include "i8254.h"
 
 //#define DEBUG_I82378
 
diff --git a/hw/i8254.c b/hw/i8254.c
index d55b221..71ea849 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -25,6 +25,7 @@
 #include "pc.h"
 #include "isa.h"
 #include "qemu-timer.h"
+#include "i8254.h"
 
 //#define DEBUG_PIT
 
diff --git a/hw/i8254.h b/hw/i8254.h
new file mode 100644
index 0000000..cd3111c
--- /dev/null
+++ b/hw/i8254.h
@@ -0,0 +1,54 @@
+/*
+ * QEMU 8253/8254 interval timer emulation
+ *
+ * Copyright (c) 2003-2004 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.
+ */
+
+#ifndef HW_I8254_H
+#define HW_I8254_H
+
+#include "hw.h"
+#include "isa.h"
+
+#define PIT_FREQ 1193182
+
+static inline ISADevice *pit_init(ISABus *bus, int base, int irq)
+{
+    ISADevice *dev;
+
+    dev = isa_create(bus, "isa-pit");
+    qdev_prop_set_uint32(&dev->qdev, "iobase", base);
+    qdev_prop_set_uint32(&dev->qdev, "irq", irq);
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
+
+void pit_set_gate(ISADevice *dev, int channel, int val);
+int pit_get_gate(ISADevice *dev, int channel);
+int pit_get_initial_count(ISADevice *dev, int channel);
+int pit_get_mode(ISADevice *dev, int channel);
+int pit_get_out(ISADevice *dev, int channel, int64_t current_time);
+
+void hpet_pit_disable(void);
+void hpet_pit_enable(void);
+
+#endif /* !HW_I8254_H */
diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c
index 163a668..ead72ae 100644
--- a/hw/mips_fulong2e.c
+++ b/hw/mips_fulong2e.c
@@ -40,6 +40,7 @@
 #include "elf.h"
 #include "vt82c686.h"
 #include "mc146818rtc.h"
+#include "i8254.h"
 #include "blockdev.h"
 #include "exec-memory.h"
 
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 63165b9..61dee4d 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -36,6 +36,7 @@
 #include "mips-bios.h"
 #include "loader.h"
 #include "mc146818rtc.h"
+#include "i8254.h"
 #include "blockdev.h"
 #include "sysbus.h"
 #include "exec-memory.h"
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index ffecefd..692f79b 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -45,6 +45,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "mc146818rtc.h"
+#include "i8254.h"
 #include "blockdev.h"
 #include "exec-memory.h"
 #include "sysbus.h"             /* SysBusDevice */
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index 1c0615c..1b3ec2d 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -22,6 +22,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "mc146818rtc.h"
+#include "i8254.h"
 #include "blockdev.h"
 #include "exec-memory.h"
 
diff --git a/hw/pc.c b/hw/pc.c
index ab94d72..435fe4d 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -36,6 +36,7 @@
 #include "elf.h"
 #include "multiboot.h"
 #include "mc146818rtc.h"
+#include "i8254.h"
 #include "msi.h"
 #include "sysbus.h"
 #include "sysemu.h"
diff --git a/hw/pc.h b/hw/pc.h
index c666ec9..b08708d 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -81,31 +81,6 @@ typedef struct GSIState {
 
 void gsi_handler(void *opaque, int n, int level);
 
-/* i8254.c */
-
-#define PIT_FREQ 1193182
-
-static inline ISADevice *pit_init(ISABus *bus, int base, int irq)
-{
-    ISADevice *dev;
-
-    dev = isa_create(bus, "isa-pit");
-    qdev_prop_set_uint32(&dev->qdev, "iobase", base);
-    qdev_prop_set_uint32(&dev->qdev, "irq", irq);
-    qdev_init_nofail(&dev->qdev);
-
-    return dev;
-}
-
-void pit_set_gate(ISADevice *dev, int channel, int val);
-int pit_get_gate(ISADevice *dev, int channel);
-int pit_get_initial_count(ISADevice *dev, int channel);
-int pit_get_mode(ISADevice *dev, int channel);
-int pit_get_out(ISADevice *dev, int channel, int64_t current_time);
-
-void hpet_pit_disable(void);
-void hpet_pit_enable(void);
-
 /* vmport.c */
 static inline void vmport_init(ISABus *bus)
 {
diff --git a/hw/pcspk.c b/hw/pcspk.c
index acb0167..43df818 100644
--- a/hw/pcspk.c
+++ b/hw/pcspk.c
@@ -27,6 +27,7 @@
 #include "isa.h"
 #include "audio/audio.h"
 #include "qemu-timer.h"
+#include "i8254.h"
 
 #define PCSPK_BUF_LEN 1792
 #define PCSPK_SAMPLE_RATE 32000
commit 5904ae4eba0928c35845720f9a630c19e48c2131
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Wed Feb 1 20:31:38 2012 +0100

    hpet: Save/restore cached RTC IRQ level
    
    In legacy mode, the HPET suppresses the RTC interrupt delivery via IRQ
    8 but keeps track of the RTC output level and applies it when legacy
    mode is turned off again. This value has to be preserved across save/
    restore as it cannot be reconstructed otherwise.
    
    To document that a raised rtc_irq_level won't survive a vmload without
    a hpet/rtc_irq_level subsection, add an explicit clearing to the reset
    handler.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/hpet.c b/hw/hpet.c
index ba36e10..76769d5 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -240,6 +240,24 @@ static int hpet_post_load(void *opaque, int version_id)
     return 0;
 }
 
+static bool hpet_rtc_irq_level_needed(void *opaque)
+{
+    HPETState *s = opaque;
+
+    return s->rtc_irq_level != 0;
+}
+
+static const VMStateDescription vmstate_hpet_rtc_irq_level = {
+    .name = "hpet/rtc_irq_level",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(rtc_irq_level, HPETState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_hpet_timer = {
     .name = "hpet_timer",
     .version_id = 1,
@@ -273,6 +291,14 @@ static const VMStateDescription vmstate_hpet = {
         VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 0,
                                     vmstate_hpet_timer, HPETTimer),
         VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection[]) {
+        {
+            .vmsd = &vmstate_hpet_rtc_irq_level,
+            .needed = hpet_rtc_irq_level_needed,
+        }, {
+            /* empty */
+        }
     }
 };
 
@@ -636,6 +662,9 @@ static void hpet_reset(DeviceState *d)
     hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
     hpet_cfg.hpet[s->hpet_id].address = sysbus_from_qdev(d)->mmio[0].addr;
     count = 1;
+
+    /* to document that the RTC lowers its output on reset as well */
+    s->rtc_irq_level = 0;
 }
 
 static void hpet_handle_rtc_irq(void *opaque, int n, int level)
commit 61b7b67df2ed10ff5ab0dcc649080bca782fdc5e
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Wed Feb 1 20:31:37 2012 +0100

    i8254: Do not raise IRQ level on reset
    
    Avoid changing the IRQ level to high on reset as it may trigger spurious
    events. Instead, open-code the effects of pit_load_count(0) in the reset
    handler.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/i8254.c b/hw/i8254.c
index 481fc7b..d55b221 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -481,7 +481,13 @@ static void pit_reset(DeviceState *dev)
         s = &pit->channels[i];
         s->mode = 3;
         s->gate = (i != 2);
-        pit_load_count(s, 0);
+        s->count_load_time = qemu_get_clock_ns(vm_clock);
+        s->count = 0x10000;
+        if (i == 0) {
+            s->next_transition_time =
+                pit_get_next_transition_time(s, s->count_load_time);
+            qemu_mod_timer(s->irq_timer, s->next_transition_time);
+        }
     }
 }
 
commit 7dfbfc7927c1f7ab9f6910768ed6d966645b5866
Author: Daniel P. Berrange <berrange at redhat.com>
Date:   Tue Feb 14 12:37:29 2012 +0000

    vnc: Don't demote authentication scheme when changing password/disabling login
    
    Currently when disabling login in VNC, the password is cleared out and the
    authentication protocol is forced to AUTH_VNC.  If you're using a stronger
    authentication protocol, this has the effect of downgrading your security
    protocol.
    
    Fix this by only changing the authentication protocol if the current
    authentication protocol is AUTH_NONE.  That ensures we're never downgrading.
    
    Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    --
    NB. This patch is derived from one posted by Anthony last year, which got
    accidentally lost after Luiz took over the QMP series work
    
      https://lists.gnu.org/archive/html/qemu-devel/2011-09/msg00392.html
    
     v1 -> v2
     - Make sure to not demote when changing password (Daniel)
     v2 -> v3
     - Rebase to latest GIT master wrt QMP changes

diff --git a/ui/vnc.c b/ui/vnc.c
index 02b71bc..8ee39bc 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2794,7 +2794,9 @@ int vnc_display_disable_login(DisplayState *ds)
     }
 
     vs->password = NULL;
-    vs->auth = VNC_AUTH_VNC;
+    if (vs->auth == VNC_AUTH_NONE) {
+        vs->auth = VNC_AUTH_VNC;
+    }
 
     return 0;
 }
@@ -2818,7 +2820,9 @@ int vnc_display_password(DisplayState *ds, const char *password)
         vs->password = NULL;
     }
     vs->password = g_strdup(password);
-    vs->auth = VNC_AUTH_VNC;
+    if (vs->auth == VNC_AUTH_NONE) {
+        vs->auth = VNC_AUTH_VNC;
+    }
 
     return 0;
 }
commit 4ed658ca925249021789d6a51fd6f99f68213f28
Author: Andreas Färber <afaerber at suse.de>
Date:   Fri Feb 17 02:47:44 2012 +0100

    qdev: Fix qdev_try_create() semantics
    
    Since QOM'ification, qdev_try_create() uses object_new() internally,
    which asserts "type != NULL" when the type is not registered.
    This was revealed by the combination of kvmclock's kvm_enabled() check
    and early QOM type registration.
    
    Check whether the class exists before calling object_new(), so that
    the caller (e.g., qdev_create) can fail gracefully, telling us which
    device could not be created.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Cc: Anthony Liguori <aliguori at codemonkey.ws>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev.c b/hw/qdev.c
index f0eb3a7..ee21d90 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -117,6 +117,9 @@ DeviceState *qdev_try_create(BusState *bus, const char *name)
 {
     DeviceState *dev;
 
+    if (object_class_by_name(name) == NULL) {
+        return NULL;
+    }
     dev = DEVICE(object_new(name));
     if (!dev) {
         return NULL;
commit 438e1c79f196f0bc9411ef8183f9906e0efbd578
Author: Andreas Färber <afaerber at suse.de>
Date:   Thu Feb 16 18:03:19 2012 +0100

    qom: Fix identifiers in documentation
    
    Fixes gtk-doc warnings.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/include/qemu/object.h b/include/qemu/object.h
index c871254..5179c0c 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -486,7 +486,7 @@ void object_finalize(void *obj);
 Object *object_dynamic_cast(Object *obj, const char *typename);
 
 /**
- * @object_dynamic_cast_assert:
+ * object_dynamic_cast_assert:
  *
  * See object_dynamic_cast() for a description of the parameters of this
  * function.  The only difference in behavior is that this function asserts
@@ -730,7 +730,7 @@ void object_property_set(Object *obj, struct Visitor *v, const char *name,
                          struct Error **errp);
 
 /**
- * @object_property_get_type:
+ * object_property_get_type:
  * @obj: the object
  * @name: the name of the property
  * @errp: returns an error if this function fails
commit a0dbf4083452cbbc8703f309c6b1f89abfa7cebe
Author: Andreas Färber <afaerber at suse.de>
Date:   Thu Feb 16 18:03:18 2012 +0100

    qom: Fix typo in Object's documentation
    
    Fixes a warning from gtk-doc.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/include/qemu/object.h b/include/qemu/object.h
index 69cc2ab..c871254 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -330,7 +330,7 @@ struct TypeInfo
 
 /**
  * OBJECT_CLASS:
- * @class: A derivative of #ObjectClas.
+ * @class: A derivative of #ObjectClass.
  *
  * Converts a class to an #ObjectClass.  Since all objects are #Objects,
  * this function will always succeed.
commit 4dcc3f5876fa638d5c35bd47be3b717ea74cc2e7
Author: Brad Smith <brad at comstyle.com>
Date:   Fri Feb 10 15:59:38 2012 -0500

    configure: Remove OpenBSD workaround for curses probe
    
    Remove the OpenBSD workaround for the curses probe. This has not been
    necessary for 5 releases now.
    
    Signed-off-by: Brad Smith <brad at comstyle.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index 9e0fdfb..037f7f7 100755
--- a/configure
+++ b/configure
@@ -1900,9 +1900,6 @@ if test "$curses" != "no" ; then
   curses_found=no
   cat > $TMPC << EOF
 #include <curses.h>
-#ifdef __OpenBSD__
-#define resize_term resizeterm
-#endif
 int main(void) {
   const char *s = curses_version();
   resize_term(0, 0);
commit ad4cf3f6b72b736ab3a41a8f4ed7c0bd4c32352f
Author: Paul Brook <paul at codesourcery.com>
Date:   Thu Feb 9 19:05:29 2012 +0000

    libcacard configure fixes
    
    libcacard is only used by system emulation.
    Only define libcacard_libs/cflags once.
    
    Signed-off-by: Paul Brook <paul at codesourcery.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index 68f9ee6..9e0fdfb 100755
--- a/configure
+++ b/configure
@@ -2569,7 +2569,7 @@ EOF
           compile_prog "$smartcard_cflags $libcacard_cflags" "$libcacard_libs"; then
             smartcard_nss="yes"
             QEMU_CFLAGS="$QEMU_CFLAGS $smartcard_cflags $libcacard_cflags"
-            LIBS="$libcacard_libs $LIBS"
+            libs_softmmu="$libcacard_libs $libs_softmmu"
         else
             if test "$smartcard_nss" = "yes"; then
                 feature_not_found "nss"
@@ -3209,6 +3209,8 @@ fi
 
 if test "$smartcard_nss" = "yes" ; then
   echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak
+  echo "libcacard_libs=$libcacard_libs" >> $config_host_mak
+  echo "libcacard_cflags=$libcacard_cflags" >> $config_host_mak
 fi
 
 if test "$usb_redir" = "yes" ; then
@@ -3628,6 +3630,9 @@ if test "$target_softmmu" = "yes" ; then
   echo "LIBS+=$libs_softmmu $target_libs_softmmu" >> $config_target_mak
   echo "HWDIR=../libhw$target_phys_bits" >> $config_target_mak
   echo "subdir-$target: subdir-libhw$target_phys_bits" >> $config_host_mak
+  if test "$smartcard_nss" = "yes" ; then
+    echo "subdir-$target: subdir-libcacard" >> $config_host_mak
+  fi
 fi
 if test "$target_user_only" = "yes" ; then
   echo "CONFIG_USER_ONLY=y" >> $config_target_mak
@@ -3639,11 +3644,6 @@ fi
 if test "$target_darwin_user" = "yes" ; then
   echo "CONFIG_DARWIN_USER=y" >> $config_target_mak
 fi
-if test "$smartcard_nss" = "yes" ; then
-  echo "subdir-$target: subdir-libcacard" >> $config_host_mak
-  echo "libcacard_libs=$libcacard_libs" >> $config_host_mak
-  echo "libcacard_cflags=$libcacard_cflags" >> $config_host_mak
-fi
 list=""
 if test ! -z "$gdb_xml_files" ; then
   for x in $gdb_xml_files; do
commit 1bbbdabd568fb62125cf214327b4fb5c5d49c694
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Jan 13 17:34:04 2012 +0100

    coroutine: switch to QSLIST
    
    QSLIST can be used for a free list, do it.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c
index 3d01075..5f43083 100644
--- a/coroutine-ucontext.c
+++ b/coroutine-ucontext.c
@@ -36,7 +36,7 @@ enum {
 };
 
 /** Free list to speed up creation */
-static QLIST_HEAD(, Coroutine) pool = QLIST_HEAD_INITIALIZER(pool);
+static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool);
 static unsigned int pool_size;
 
 typedef struct {
@@ -92,7 +92,7 @@ static void __attribute__((destructor)) coroutine_cleanup(void)
     Coroutine *co;
     Coroutine *tmp;
 
-    QLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
+    QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) {
         g_free(DO_UPCAST(CoroutineUContext, base, co)->stack);
         g_free(co);
     }
@@ -175,9 +175,9 @@ Coroutine *qemu_coroutine_new(void)
 {
     Coroutine *co;
 
-    co = QLIST_FIRST(&pool);
+    co = QSLIST_FIRST(&pool);
     if (co) {
-        QLIST_REMOVE(co, pool_next);
+        QSLIST_REMOVE_HEAD(&pool, pool_next);
         pool_size--;
     } else {
         co = coroutine_new();
@@ -190,7 +190,7 @@ void qemu_coroutine_delete(Coroutine *co_)
     CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
 
     if (pool_size < POOL_MAX_SIZE) {
-        QLIST_INSERT_HEAD(&pool, &co->base, pool_next);
+        QSLIST_INSERT_HEAD(&pool, &co->base, pool_next);
         co->base.caller = NULL;
         pool_size++;
         return;
diff --git a/qemu-coroutine-int.h b/qemu-coroutine-int.h
index d495615..0f1bd80 100644
--- a/qemu-coroutine-int.h
+++ b/qemu-coroutine-int.h
@@ -37,7 +37,7 @@ struct Coroutine {
     CoroutineEntry *entry;
     void *entry_arg;
     Coroutine *caller;
-    QLIST_ENTRY(Coroutine) pool_next;
+    QSLIST_ENTRY(Coroutine) pool_next;
     QTAILQ_ENTRY(Coroutine) co_queue_next;
 };
 
commit cf904cfa7cf8fcd54ca4ad756e26997d1e7383fb
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Jan 13 17:34:03 2012 +0100

    qemu-queue: drop QCIRCLEQ
    
    The main advantage of circular lists (the fact that the head node
    has the same memory layout as any other node) is completely negated
    by the implementation in qemu-queue.h.  Not surprisingly, nobody
    uses QCIRCLEQ.  While this might change if RCU is ever adopted by
    QEMU, the QLIST is also RCU-friendly and in fact it is used in a
    RCU-like manner by 9pfs already.  So, just kill QCIRCLEQ.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/qemu-queue.h b/qemu-queue.h
index a8ecfaa..74d7122 100644
--- a/qemu-queue.h
+++ b/qemu-queue.h
@@ -3,7 +3,7 @@
 /*
  * Qemu version: Copy from netbsd, removed debug code, removed some of
  * the implementations.  Left in singly-linked lists, lists, simple
- * queues, tail queues and circular queues.
+ * queues, and tail queues.
  */
 
 /*
@@ -41,8 +41,8 @@
 #define QEMU_SYS_QUEUE_H_
 
 /*
- * This file defines five types of data structures: singly-linked lists,
- * lists, simple queues, tail queues, and circular queues.
+ * This file defines four types of data structures: singly-linked lists,
+ * lists, simple queues, and tail queues.
  *
  * A singly-linked list is headed by a single forward pointer. The
  * elements are singly linked for minimum space and pointer manipulation
@@ -75,14 +75,6 @@
  * after an existing element, at the head of the list, or at the end of
  * the list. A tail queue may be traversed in either direction.
  *
- * A circle queue is headed by a pair of pointers, one to the head of the
- * list and the other to the tail of the list. The elements are doubly
- * linked so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before or after
- * an existing element, at the head of the list, or at the end of the list.
- * A circle queue may be traversed in either direction, but has a more
- * complex end of list detection.
- *
  * For details on the use of these macros, see the queue(3) manual page.
  */
 
@@ -419,112 +411,4 @@ struct {                                                                \
 #define QTAILQ_PREV(elm, headname, field) \
         (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
 
-
-/*
- * Circular queue definitions.
- */
-#define QCIRCLEQ_HEAD(name, type)                                       \
-struct name {                                                           \
-        struct type *cqh_first;         /* first element */             \
-        struct type *cqh_last;          /* last element */              \
-}
-
-#define QCIRCLEQ_HEAD_INITIALIZER(head)                                 \
-        { (void *)&head, (void *)&head }
-
-#define QCIRCLEQ_ENTRY(type)                                            \
-struct {                                                                \
-        struct type *cqe_next;          /* next element */              \
-        struct type *cqe_prev;          /* previous element */          \
-}
-
-/*
- * Circular queue functions.
- */
-#define QCIRCLEQ_INIT(head) do {                                        \
-        (head)->cqh_first = (void *)(head);                             \
-        (head)->cqh_last = (void *)(head);                              \
-} while (/*CONSTCOND*/0)
-
-#define QCIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {           \
-        (elm)->field.cqe_next = (listelm)->field.cqe_next;              \
-        (elm)->field.cqe_prev = (listelm);                              \
-        if ((listelm)->field.cqe_next == (void *)(head))                \
-                (head)->cqh_last = (elm);                               \
-        else                                                            \
-                (listelm)->field.cqe_next->field.cqe_prev = (elm);      \
-        (listelm)->field.cqe_next = (elm);                              \
-} while (/*CONSTCOND*/0)
-
-#define QCIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {          \
-        (elm)->field.cqe_next = (listelm);                              \
-        (elm)->field.cqe_prev = (listelm)->field.cqe_prev;              \
-        if ((listelm)->field.cqe_prev == (void *)(head))                \
-                (head)->cqh_first = (elm);                              \
-        else                                                            \
-                (listelm)->field.cqe_prev->field.cqe_next = (elm);      \
-        (listelm)->field.cqe_prev = (elm);                              \
-} while (/*CONSTCOND*/0)
-
-#define QCIRCLEQ_INSERT_HEAD(head, elm, field) do {                     \
-        (elm)->field.cqe_next = (head)->cqh_first;                      \
-        (elm)->field.cqe_prev = (void *)(head);                         \
-        if ((head)->cqh_last == (void *)(head))                         \
-                (head)->cqh_last = (elm);                               \
-        else                                                            \
-                (head)->cqh_first->field.cqe_prev = (elm);              \
-        (head)->cqh_first = (elm);                                      \
-} while (/*CONSTCOND*/0)
-
-#define QCIRCLEQ_INSERT_TAIL(head, elm, field) do {                     \
-        (elm)->field.cqe_next = (void *)(head);                         \
-        (elm)->field.cqe_prev = (head)->cqh_last;                       \
-        if ((head)->cqh_first == (void *)(head))                        \
-                (head)->cqh_first = (elm);                              \
-        else                                                            \
-                (head)->cqh_last->field.cqe_next = (elm);               \
-        (head)->cqh_last = (elm);                                       \
-} while (/*CONSTCOND*/0)
-
-#define QCIRCLEQ_REMOVE(head, elm, field) do {                          \
-        if ((elm)->field.cqe_next == (void *)(head))                    \
-                (head)->cqh_last = (elm)->field.cqe_prev;               \
-        else                                                            \
-                (elm)->field.cqe_next->field.cqe_prev =                 \
-                    (elm)->field.cqe_prev;                              \
-        if ((elm)->field.cqe_prev == (void *)(head))                    \
-                (head)->cqh_first = (elm)->field.cqe_next;              \
-        else                                                            \
-                (elm)->field.cqe_prev->field.cqe_next =                 \
-                    (elm)->field.cqe_next;                              \
-} while (/*CONSTCOND*/0)
-
-#define QCIRCLEQ_FOREACH(var, head, field)                              \
-        for ((var) = ((head)->cqh_first);                               \
-                (var) != (const void *)(head);                          \
-                (var) = ((var)->field.cqe_next))
-
-#define QCIRCLEQ_FOREACH_REVERSE(var, head, field)                      \
-        for ((var) = ((head)->cqh_last);                                \
-                (var) != (const void *)(head);                          \
-                (var) = ((var)->field.cqe_prev))
-
-/*
- * Circular queue access methods.
- */
-#define QCIRCLEQ_EMPTY(head)             ((head)->cqh_first == (void *)(head))
-#define QCIRCLEQ_FIRST(head)             ((head)->cqh_first)
-#define QCIRCLEQ_LAST(head)              ((head)->cqh_last)
-#define QCIRCLEQ_NEXT(elm, field)        ((elm)->field.cqe_next)
-#define QCIRCLEQ_PREV(elm, field)        ((elm)->field.cqe_prev)
-
-#define QCIRCLEQ_LOOP_NEXT(head, elm, field)                            \
-        (((elm)->field.cqe_next == (void *)(head))                      \
-            ? ((head)->cqh_first)                                       \
-            : (elm->field.cqe_next))
-#define QCIRCLEQ_LOOP_PREV(head, elm, field)                            \
-        (((elm)->field.cqe_prev == (void *)(head))                      \
-            ? ((head)->cqh_last)                                        \
-            : (elm->field.cqe_prev))
-
 #endif  /* !QEMU_SYS_QUEUE_H_ */
commit 6095aa88e4cec8ea0af3944ffc0e667d04d47362
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Jan 13 17:34:02 2012 +0100

    qemu-queue: add QSLIST
    
    Based on http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/sys/queue.h?rev=1.53
    with only the prefix change.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/qemu-queue.h b/qemu-queue.h
index 2214230..a8ecfaa 100644
--- a/qemu-queue.h
+++ b/qemu-queue.h
@@ -2,8 +2,8 @@
 
 /*
  * Qemu version: Copy from netbsd, removed debug code, removed some of
- * the implementations.  Left in lists, simple queues, tail queues and
- * circular queues.
+ * the implementations.  Left in singly-linked lists, lists, simple
+ * queues, tail queues and circular queues.
  */
 
 /*
@@ -41,9 +41,19 @@
 #define QEMU_SYS_QUEUE_H_
 
 /*
- * This file defines four types of data structures:
+ * This file defines five types of data structures: singly-linked lists,
  * lists, simple queues, tail queues, and circular queues.
  *
+ * A singly-linked list is headed by a single forward pointer. The
+ * elements are singly linked for minimum space and pointer manipulation
+ * overhead at the expense of O(n) removal for arbitrary elements. New
+ * elements can be added to the list after an existing element or at the
+ * head of the list.  Elements being removed from the head of the list
+ * should use the explicit macro for this purpose for optimum
+ * efficiency. A singly-linked list may only be traversed in the forward
+ * direction.  Singly-linked lists are ideal for applications with large
+ * datasets and few or no removals or for implementing a LIFO queue.
+ *
  * A list is headed by a single forward pointer (or an array of forward
  * pointers for a hash table header). The elements are doubly linked
  * so that an arbitrary element can be removed without a need to
@@ -161,6 +171,64 @@ struct {                                                                \
 
 
 /*
+ * Singly-linked List definitions.
+ */
+#define QSLIST_HEAD(name, type)                                          \
+struct name {                                                           \
+        struct type *slh_first; /* first element */                     \
+}
+
+#define QSLIST_HEAD_INITIALIZER(head)                                    \
+        { NULL }
+
+#define QSLIST_ENTRY(type)                                               \
+struct {                                                                \
+        struct type *sle_next;  /* next element */                      \
+}
+
+/*
+ * Singly-linked List functions.
+ */
+#define QSLIST_INIT(head) do {                                           \
+        (head)->slh_first = NULL;                                       \
+} while (/*CONSTCOND*/0)
+
+#define QSLIST_INSERT_AFTER(slistelm, elm, field) do {                   \
+        (elm)->field.sle_next = (slistelm)->field.sle_next;             \
+        (slistelm)->field.sle_next = (elm);                             \
+} while (/*CONSTCOND*/0)
+
+#define QSLIST_INSERT_HEAD(head, elm, field) do {                        \
+        (elm)->field.sle_next = (head)->slh_first;                      \
+        (head)->slh_first = (elm);                                      \
+} while (/*CONSTCOND*/0)
+
+#define QSLIST_REMOVE_HEAD(head, field) do {                             \
+        (head)->slh_first = (head)->slh_first->field.sle_next;          \
+} while (/*CONSTCOND*/0)
+
+#define QSLIST_REMOVE_AFTER(slistelm, field) do {                        \
+        (slistelm)->field.sle_next =                                    \
+            QSLIST_NEXT(QSLIST_NEXT((slistelm), field), field);           \
+} while (/*CONSTCOND*/0)
+
+#define QSLIST_FOREACH(var, head, field)                                 \
+        for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next)
+
+#define QSLIST_FOREACH_SAFE(var, head, field, tvar)                      \
+        for ((var) = QSLIST_FIRST((head));                               \
+            (var) && ((tvar) = QSLIST_NEXT((var), field), 1);            \
+            (var) = (tvar))
+
+/*
+ * Singly-linked List access methods.
+ */
+#define QSLIST_EMPTY(head)       ((head)->slh_first == NULL)
+#define QSLIST_FIRST(head)       ((head)->slh_first)
+#define QSLIST_NEXT(elm, field)  ((elm)->field.sle_next)
+
+
+/*
  * Simple queue definitions.
  */
 #define QSIMPLEQ_HEAD(name, type)                                       \
commit 31552529a7eba5011dac74bab18a852860c45c9d
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Jan 13 17:34:01 2012 +0100

    notifier: switch to QLIST
    
    Notifiers do not need to access both ends of the list, and using
    a QLIST also simplifies the API.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/input.c b/input.c
index 9ade63f..b618ea4 100644
--- a/input.c
+++ b/input.c
@@ -268,5 +268,5 @@ void qemu_add_mouse_mode_change_notifier(Notifier *notify)
 
 void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
 {
-    notifier_list_remove(&mouse_mode_notifiers, notify);
+    notifier_remove(notify);
 }
diff --git a/migration.c b/migration.c
index 37af438..00fa1e3 100644
--- a/migration.c
+++ b/migration.c
@@ -335,7 +335,7 @@ void add_migration_state_change_notifier(Notifier *notify)
 
 void remove_migration_state_change_notifier(Notifier *notify)
 {
-    notifier_list_remove(&migration_state_notifiers, notify);
+    notifier_remove(notify);
 }
 
 bool migration_is_active(MigrationState *s)
diff --git a/notify.c b/notify.c
index c104495..12282a6 100644
--- a/notify.c
+++ b/notify.c
@@ -18,24 +18,24 @@
 
 void notifier_list_init(NotifierList *list)
 {
-    QTAILQ_INIT(&list->notifiers);
+    QLIST_INIT(&list->notifiers);
 }
 
 void notifier_list_add(NotifierList *list, Notifier *notifier)
 {
-    QTAILQ_INSERT_HEAD(&list->notifiers, notifier, node);
+    QLIST_INSERT_HEAD(&list->notifiers, notifier, node);
 }
 
-void notifier_list_remove(NotifierList *list, Notifier *notifier)
+void notifier_remove(Notifier *notifier)
 {
-    QTAILQ_REMOVE(&list->notifiers, notifier, node);
+    QLIST_REMOVE(notifier, node);
 }
 
 void notifier_list_notify(NotifierList *list, void *data)
 {
     Notifier *notifier, *next;
 
-    QTAILQ_FOREACH_SAFE(notifier, &list->notifiers, node, next) {
+    QLIST_FOREACH_SAFE(notifier, &list->notifiers, node, next) {
         notifier->notify(notifier, data);
     }
 }
diff --git a/notify.h b/notify.h
index 54fc57c..03cf26c 100644
--- a/notify.h
+++ b/notify.h
@@ -21,22 +21,22 @@ typedef struct Notifier Notifier;
 struct Notifier
 {
     void (*notify)(Notifier *notifier, void *data);
-    QTAILQ_ENTRY(Notifier) node;
+    QLIST_ENTRY(Notifier) node;
 };
 
 typedef struct NotifierList
 {
-    QTAILQ_HEAD(, Notifier) notifiers;
+    QLIST_HEAD(, Notifier) notifiers;
 } NotifierList;
 
 #define NOTIFIER_LIST_INITIALIZER(head) \
-    { QTAILQ_HEAD_INITIALIZER((head).notifiers) }
+    { QLIST_HEAD_INITIALIZER((head).notifiers) }
 
 void notifier_list_init(NotifierList *list);
 
 void notifier_list_add(NotifierList *list, Notifier *notifier);
 
-void notifier_list_remove(NotifierList *list, Notifier *notifier);
+void notifier_remove(Notifier *notifier);
 
 void notifier_list_notify(NotifierList *list, void *data);
 
diff --git a/qemu-timer.c b/qemu-timer.c
index a22f27e..d7f56e5 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -453,7 +453,7 @@ void qemu_register_clock_reset_notifier(QEMUClock *clock, Notifier *notifier)
 
 void qemu_unregister_clock_reset_notifier(QEMUClock *clock, Notifier *notifier)
 {
-    notifier_list_remove(&clock->reset_notifiers, notifier);
+    notifier_remove(notifier);
 }
 
 void init_clocks(void)
diff --git a/vl.c b/vl.c
index 9609d2b..d8a521a 100644
--- a/vl.c
+++ b/vl.c
@@ -2093,7 +2093,7 @@ void qemu_add_exit_notifier(Notifier *notify)
 
 void qemu_remove_exit_notifier(Notifier *notify)
 {
-    notifier_list_remove(&exit_notifiers, notify);
+    notifier_remove(notify);
 }
 
 static void qemu_run_exit_notifiers(void)
commit c77de088b1067fc0e0df322e5bac60a3a26a0613
Merge: 3d7f572... e595079...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Feb 17 06:50:58 2012 -0600

    Merge remote-tracking branch 'bonzini/nbd-for-anthony' into staging
    
    * bonzini/nbd-for-anthony:
      nbd: add git tree to MAINTAINERS
      open /dev/nbd in nbd_client_thread
      do not chdir(/) in qemu-nbd before opening all files

commit 3d7f5721409d10d33f03891addf67e0984cf319e
Merge: a19255a... 13a16f1...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Feb 17 06:50:07 2012 -0600

    Merge remote-tracking branch 'pmaydell/arm-devs.for-upstream' into staging
    
    * pmaydell/arm-devs.for-upstream: (22 commits)
      hw/pl031: Actually raise interrupt on timer expiry
      MAINTAINERS: Add hw/highbank.c maintainer
      Remove unnecessary includes of primecell.h
      hw/primecell.h: Remove obsolete pl080_init() declaration
      hw/arm_sysctl: Drop legacy init function
      hw/vexpress.c: Add vexpress-a15 machine
      arm_boot: Pass base address of GIC CPU interface, not whole GIC
      hw/vexpress.c: Instantiate the motherboard CLCD
      hw/vexpress.c: Factor out daughterboard-specific initialization
      hw/vexpress.c: Move secondary CPU boot code to SRAM
      hw/vexpress.c: Make motherboard peripheral memory map table-driven
      hw/a15mpcore.c: Add Cortex-A15 private peripheral model
      MAINTAINERS: Add maintainers for Exynos SOC.
      Exynos4210: added display controller implementation
      hw/exynos4210.c: Add LAN support for SMDKC210.
      hw/lan9118: Add basic 16-bit mode support.
      ARM: exynos4210: MCT support.
      ARM: exynos4210: basic Power Management Unit implementation
      ARM: exynos4210: PWM support.
      ARM: exynos4210: UART support
      ...

commit a19255a369f0ef34dfbbc1ed2631e68fbbebb8ce
Merge: 9de36b1... 3a0c6c4...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Feb 17 06:48:47 2012 -0600

    Merge remote-tracking branch 'stefanha/trivial-patches' into staging
    
    * stefanha/trivial-patches:
      linux-user: brk() debugging
      virtio: Remove unneeded g_free() check in virtio_cleanup()
      net: remove extra spaces in help messages
      fmopl: Fix typo in function name
      vl.c: Fix typo in variable name
      ide: fix compilation errors when DEBUG_IDE is set
      cpu-exec.c: Correct comment about this file and indentation cleanup
      CODING_STYLE: Clarify style for enum and function type names
      linux-user: fail execve() if env/args too big

commit e5950790cb8c447867752faa62d8471d55298d58
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Jan 18 12:48:19 2012 +0100

    nbd: add git tree to MAINTAINERS
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/MAINTAINERS b/MAINTAINERS
index 173e893..6a9c981 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -510,6 +510,7 @@ S: Odd Fixes
 F: block/nbd.c
 F: nbd.*
 F: qemu-nbd.c
+T: git://github.com/bonzini/qemu.git nbd-next
 
 SLIRP
 M: Jan Kiszka <jan.kiszka at siemens.com>
commit a6ac2313a83a6c3ed69c221ef8bed91676f078e9
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Dec 6 09:07:00 2011 +0100

    open /dev/nbd in nbd_client_thread
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/qemu-nbd.c b/qemu-nbd.c
index e189cf8..d4e7041 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -37,7 +37,6 @@
 
 static NBDExport *exp;
 static int verbose;
-static char *device;
 static char *srcpath;
 static char *sockpath;
 static bool sigterm_reported;
@@ -178,6 +177,7 @@ static void termsig_handler(int signum)
 
 static void *show_parts(void *arg)
 {
+    char *device = arg;
     int nbd;
 
     /* linux just needs an open() to trigger
@@ -194,11 +194,11 @@ static void *show_parts(void *arg)
 
 static void *nbd_client_thread(void *arg)
 {
-    int fd = *(int *)arg;
+    char *device = arg;
     off_t size;
     size_t blocksize;
     uint32_t nbdflags;
-    int sock;
+    int fd, sock;
     int ret;
     pthread_t show_parts_thread;
 
@@ -213,13 +213,20 @@ static void *nbd_client_thread(void *arg)
         goto out;
     }
 
+    fd = open(device, O_RDWR);
+    if (fd == -1) {
+        /* Linux-only, we can use %m in printf.  */
+        fprintf(stderr, "Failed to open %s: %m", device);
+        goto out;
+    }
+
     ret = nbd_init(fd, sock, nbdflags, size, blocksize);
     if (ret == -1) {
         goto out;
     }
 
     /* update partition table */
-    pthread_create(&show_parts_thread, NULL, show_parts, NULL);
+    pthread_create(&show_parts_thread, NULL, show_parts, device);
 
     if (verbose) {
         fprintf(stderr, "NBD device %s is now connected to %s\n",
@@ -273,6 +280,7 @@ int main(int argc, char **argv)
     uint32_t nbdflags = 0;
     bool disconnect = false;
     const char *bindto = "0.0.0.0";
+    char *device = NULL;
     int port = NBD_DEFAULT_PORT;
     off_t fd_size;
     const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t";
@@ -466,19 +474,9 @@ int main(int argc, char **argv)
         }
     }
 
-    if (device) {
-        /* Open before spawning new threads.  In the future, we may
-         * drop privileges after opening.
-         */
-        fd = open(device, O_RDWR);
-        if (fd == -1) {
-            err(EXIT_FAILURE, "Failed to open %s", device);
-        }
-
-        if (sockpath == NULL) {
-            sockpath = g_malloc(128);
-            snprintf(sockpath, 128, SOCKET_PATH, basename(device));
-        }
+    if (device != NULL && sockpath == NULL) {
+        sockpath = g_malloc(128);
+        snprintf(sockpath, 128, SOCKET_PATH, basename(device));
     }
 
     bdrv_init();
@@ -513,7 +511,7 @@ int main(int argc, char **argv)
     if (device) {
         int ret;
 
-        ret = pthread_create(&client_thread, NULL, nbd_client_thread, &fd);
+        ret = pthread_create(&client_thread, NULL, nbd_client_thread, device);
         if (ret != 0) {
             errx(EXIT_FAILURE, "Failed to create client thread: %s",
                  strerror(ret));
commit 9faf31b68f049ca6432a1ef086a76344ff2a2357
Author: Michael Tokarev <mjt at tls.msk.ru>
Date:   Mon Jan 16 18:37:44 2012 +0400

    do not chdir(/) in qemu-nbd before opening all files
    
    When qemu-nbd becomes a daemon it calls daemon(3) with
    nochdir=0, so daemon(3) changes current directory to /.
    But at this time, qemu-nbd did not open any user-specified
    files yet, so by changing current directory, all non-absolute
    paths becomes wrong.  The solution is to pass nochdir=1 to
    daemon(3) function, and to chdir("/") after all init has
    been performed, before entering the main loop, -- just like
    a good daemon should do.
    
    This patch is applicable for -stable.
    
    Signed-off-by: Michael Tokarev <mjt at tls.msk.ru>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/qemu-nbd.c b/qemu-nbd.c
index eb61c33..e189cf8 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -429,7 +429,7 @@ int main(int argc, char **argv)
         pid = fork();
         if (pid == 0) {
             close(stderr_fd[0]);
-            ret = qemu_daemon(0, 0);
+            ret = qemu_daemon(1, 0);
 
             /* Temporarily redirect stderr to the parent's pipe...  */
             dup2(stderr_fd[1], STDERR_FILENO);
@@ -527,6 +527,12 @@ int main(int argc, char **argv)
     qemu_set_fd_handler2(fd, nbd_can_accept, nbd_accept, NULL,
                          (void *)(uintptr_t)fd);
 
+    /* now when the initialization is (almost) complete, chdir("/")
+     * to free any busy filesystems */
+    if (chdir("/") < 0) {
+        err(EXIT_FAILURE, "Could not chdir to root directory");
+    }
+
     do {
         main_loop_wait(false);
     } while (!sigterm_reported && (persistent || !nbd_started || nb_fds > 0));
commit 13a16f1d91fc7a46b65b22a33f6ffea1b826a097
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Feb 16 09:56:10 2012 +0000

    hw/pl031: Actually raise interrupt on timer expiry
    
    Fix a typo in pl031_interrupt() which meant we were setting a bit
    in the interrupt mask rather than the interrupt status register
    and thus not actually raising an interrupt. This fix allows the
    rtctest program from the kernel's Documentation/rtc.txt to pass
    rather than hanging.
    
    Reported-by: Daniel Forsgren <daniel.forsgren at enea.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Andreas Färber <afaerber at suse.de>

diff --git a/hw/pl031.c b/hw/pl031.c
index 05b5b11..69abc4f 100644
--- a/hw/pl031.c
+++ b/hw/pl031.c
@@ -76,7 +76,7 @@ static void pl031_interrupt(void * opaque)
 {
     pl031_state *s = (pl031_state *)opaque;
 
-    s->im = 1;
+    s->is = 1;
     DPRINTF("Alarm raised\n");
     pl031_update(s);
 }
commit 766fd09fb3d8c51cdca70b703f9ce16fb1f855a4
Author: Mark Langsdorf <mark.langsdorf at calxeda.com>
Date:   Thu Feb 16 09:56:10 2012 +0000

    MAINTAINERS: Add hw/highbank.c maintainer
    
    Signed-off-by: Mark Langsdorf <mark.langsdorf at calxeda.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/MAINTAINERS b/MAINTAINERS
index e55ea0f..8eb80ea 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -191,6 +191,12 @@ M: Dmitry Solodkiy <d.solodkiy at samsung.com>
 S: Maintained
 F: hw/exynos*
 
+Calxeda Highbank
+M: Mark Langsdorf <mark.langsdorf at calxeda.com>
+S: Supported
+F: hw/highbank.c
+F: hw/xgmac.c
+
 Gumstix
 M: qemu-devel at nongnu.org
 S: Orphan
commit 22168e666033c78977d5864e808375ea256b2882
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Feb 16 09:56:10 2012 +0000

    Remove unnecessary includes of primecell.h
    
    The primecell.h header now only has the definitions of constants
    indicating the usage of the arm_sysctl GPIO lines; remove obsolete
    includes of it from source files which don't care about those GPIO
    lines.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/highbank.c b/hw/highbank.c
index b28b464..489c00e 100644
--- a/hw/highbank.c
+++ b/hw/highbank.c
@@ -19,7 +19,6 @@
 
 #include "sysbus.h"
 #include "arm-misc.h"
-#include "primecell.h"
 #include "devices.h"
 #include "loader.h"
 #include "net.h"
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index 294d7da..5b06c81 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -8,7 +8,6 @@
  */
 
 #include "sysbus.h"
-#include "primecell.h"
 #include "devices.h"
 #include "boards.h"
 #include "arm-misc.h"
diff --git a/hw/pl022.c b/hw/pl022.c
index 03bf63c..60e35da 100644
--- a/hw/pl022.c
+++ b/hw/pl022.c
@@ -9,7 +9,6 @@
 
 #include "sysbus.h"
 #include "ssi.h"
-#include "primecell.h"
 
 //#define DEBUG_PL022 1
 
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 1903db6..b9102f4 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -9,7 +9,6 @@
 
 #include "sysbus.h"
 #include "arm-misc.h"
-#include "primecell.h"
 #include "devices.h"
 #include "net.h"
 #include "sysemu.h"
commit 2a9577034acf77300ce3aa58c3ebffc5949ce96d
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Feb 16 09:56:10 2012 +0000

    hw/primecell.h: Remove obsolete pl080_init() declaration
    
    Remove an obsolete declaration of pl080_init(), which has been
    incorrect since the conversion of pl080 to qdev back in 2009.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/primecell.h b/hw/primecell.h
index e709ad3..7337c3b 100644
--- a/hw/primecell.h
+++ b/hw/primecell.h
@@ -5,9 +5,6 @@
 /* Also includes some devices that are currently only used by the
    ARM boards.  */
 
-/* pl080.c */
-void *pl080_init(uint32_t base, qemu_irq irq, int nchannels);
-
 /* arm_sysctl GPIO lines */
 #define ARM_SYSCTL_GPIO_MMC_WPROT 0
 #define ARM_SYSCTL_GPIO_MMC_CARDIN 1
commit 54de1e5b3a8f02ba5c89606023f6351261068894
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Feb 16 09:56:09 2012 +0000

    hw/arm_sysctl: Drop legacy init function
    
    Drop the legacy init function arm_sysctl_init(), since it has no
    users left any more. This allows us to drop the awkward '1' from
    the actual device init function.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Andreas Färber <afaerber at suse.de>

diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index 149c639..5f1237b 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -378,7 +378,7 @@ static void arm_sysctl_gpio_set(void *opaque, int line, int level)
     }
 }
 
-static int arm_sysctl_init1(SysBusDevice *dev)
+static int arm_sysctl_init(SysBusDevice *dev)
 {
     arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev);
 
@@ -389,18 +389,6 @@ static int arm_sysctl_init1(SysBusDevice *dev)
     return 0;
 }
 
-/* Legacy helper function.  */
-void arm_sysctl_init(uint32_t base, uint32_t sys_id, uint32_t proc_id)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "realview_sysctl");
-    qdev_prop_set_uint32(dev, "sys_id", sys_id);
-    qdev_init_nofail(dev);
-    qdev_prop_set_uint32(dev, "proc_id", proc_id);
-    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
-}
-
 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),
@@ -412,7 +400,7 @@ 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;
+    k->init = arm_sysctl_init;
     dc->reset = arm_sysctl_reset;
     dc->vmsd = &vmstate_arm_sysctl;
     dc->props = arm_sysctl_properties;
diff --git a/hw/primecell.h b/hw/primecell.h
index de7d6f2..e709ad3 100644
--- a/hw/primecell.h
+++ b/hw/primecell.h
@@ -8,9 +8,6 @@
 /* pl080.c */
 void *pl080_init(uint32_t base, qemu_irq irq, int nchannels);
 
-/* arm_sysctl.c */
-void arm_sysctl_init(uint32_t base, uint32_t sys_id, uint32_t proc_id);
-
 /* arm_sysctl GPIO lines */
 #define ARM_SYSCTL_GPIO_MMC_WPROT 0
 #define ARM_SYSCTL_GPIO_MMC_CARDIN 1
commit 961f195e6c874de0473a23344be18d567d25dc39
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Feb 16 09:56:09 2012 +0000

    hw/vexpress.c: Add vexpress-a15 machine
    
    Add the vexpress-a15 machine, and the A-Series memory map it uses.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Andreas Färber <afaerber at suse.de>

diff --git a/hw/vexpress.c b/hw/vexpress.c
index aae9d81..b9aafec 100644
--- a/hw/vexpress.c
+++ b/hw/vexpress.c
@@ -103,6 +103,41 @@ static target_phys_addr_t motherboard_legacy_map[] = {
     [VE_USB] = 0x4f000000,
 };
 
+static target_phys_addr_t motherboard_aseries_map[] = {
+    /* CS0: 0x00000000 .. 0x0c000000 */
+    [VE_NORFLASH0] = 0x00000000,
+    [VE_NORFLASH0ALIAS] = 0x08000000,
+    /* CS4: 0x0c000000 .. 0x10000000 */
+    [VE_NORFLASH1] = 0x0c000000,
+    /* CS5: 0x10000000 .. 0x14000000 */
+    /* CS1: 0x14000000 .. 0x18000000 */
+    [VE_SRAM] = 0x14000000,
+    /* CS2: 0x18000000 .. 0x1c000000 */
+    [VE_VIDEORAM] = 0x18000000,
+    [VE_ETHERNET] = 0x1a000000,
+    [VE_USB] = 0x1b000000,
+    /* CS3: 0x1c000000 .. 0x20000000 */
+    [VE_DAPROM] = 0x1c000000,
+    [VE_SYSREGS] = 0x1c010000,
+    [VE_SP810] = 0x1c020000,
+    [VE_SERIALPCI] = 0x1c030000,
+    [VE_PL041] = 0x1c040000,
+    [VE_MMCI] = 0x1c050000,
+    [VE_KMI0] = 0x1c060000,
+    [VE_KMI1] = 0x1c070000,
+    [VE_UART0] = 0x1c090000,
+    [VE_UART1] = 0x1c0a0000,
+    [VE_UART2] = 0x1c0b0000,
+    [VE_UART3] = 0x1c0c0000,
+    [VE_WDT] = 0x1c0f0000,
+    [VE_TIMER01] = 0x1c110000,
+    [VE_TIMER23] = 0x1c120000,
+    [VE_SERIALDVI] = 0x1c160000,
+    [VE_RTC] = 0x1c170000,
+    [VE_COMPACTFLASH] = 0x1c1a0000,
+    [VE_CLCD] = 0x1c1f0000,
+};
+
 /* Structure defining the peculiarities of a specific daughterboard */
 
 typedef struct VEDBoardInfo VEDBoardInfo;
@@ -218,6 +253,91 @@ static const VEDBoardInfo a9_daughterboard = {
     .init = a9_daughterboard_init,
 };
 
+static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
+                                   ram_addr_t ram_size,
+                                   const char *cpu_model,
+                                   qemu_irq *pic, uint32_t *proc_id)
+{
+    int n;
+    CPUState *env = NULL;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
+    qemu_irq cpu_irq[4];
+    DeviceState *dev;
+    SysBusDevice *busdev;
+
+    if (!cpu_model) {
+        cpu_model = "cortex-a15";
+    }
+
+    *proc_id = 0x14000217;
+
+    for (n = 0; n < smp_cpus; n++) {
+        qemu_irq *irqp;
+        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];
+    }
+
+    if (ram_size > 0x80000000) {
+        fprintf(stderr, "vexpress-a15: cannot model more than 2GB RAM\n");
+        exit(1);
+    }
+
+    memory_region_init_ram(ram, "vexpress.highmem", ram_size);
+    vmstate_register_ram_global(ram);
+    /* RAM is from 0x80000000 upwards; there is no low-memory alias for it. */
+    memory_region_add_subregion(sysmem, 0x80000000, ram);
+
+    /* 0x2c000000 A15MPCore private memory region (GIC) */
+    dev = qdev_create(NULL, "a15mpcore_priv");
+    qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+    qdev_init_nofail(dev);
+    busdev = sysbus_from_qdev(dev);
+    sysbus_mmio_map(busdev, 0, 0x2c000000);
+    for (n = 0; n < smp_cpus; n++) {
+        sysbus_connect_irq(busdev, n, cpu_irq[n]);
+    }
+    /* Interrupts [42:0] are from the motherboard;
+     * [47:43] are reserved; [63:48] are daughterboard
+     * peripherals. Note that some documentation numbers
+     * external interrupts starting from 32 (because there
+     * are internal interrupts 0..31).
+     */
+    for (n = 0; n < 64; n++) {
+        pic[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    /* A15 daughterboard peripherals: */
+
+    /* 0x20000000: CoreSight interfaces: not modelled */
+    /* 0x2a000000: PL301 AXI interconnect: not modelled */
+    /* 0x2a420000: SCC: not modelled */
+    /* 0x2a430000: system counter: not modelled */
+    /* 0x2b000000: HDLCD controller: not modelled */
+    /* 0x2b060000: SP805 watchdog: not modelled */
+    /* 0x2b0a0000: PL341 dynamic memory controller: not modelled */
+    /* 0x2e000000: system SRAM */
+    memory_region_init_ram(sram, "vexpress.a15sram", 0x10000);
+    vmstate_register_ram_global(sram);
+    memory_region_add_subregion(sysmem, 0x2e000000, sram);
+
+    /* 0x7ffb0000: DMA330 DMA controller: not modelled */
+    /* 0x7ffd0000: PL354 static memory controller: not modelled */
+}
+
+static const VEDBoardInfo a15_daughterboard = {
+    .motherboard_map = motherboard_aseries_map,
+    .loader_start = 0x80000000,
+    .gic_cpu_if_addr = 0x2c002000,
+    .init = a15_daughterboard_init,
+};
+
 static void vexpress_common_init(const VEDBoardInfo *daughterboard,
                                  ram_addr_t ram_size,
                                  const char *boot_device,
@@ -333,6 +453,18 @@ static void vexpress_a9_init(ram_addr_t ram_size,
                          kernel_cmdline, initrd_filename, cpu_model);
 }
 
+static void vexpress_a15_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)
+{
+    vexpress_common_init(&a15_daughterboard,
+                         ram_size, boot_device, kernel_filename,
+                         kernel_cmdline, initrd_filename, cpu_model);
+}
+
 static QEMUMachine vexpress_a9_machine = {
     .name = "vexpress-a9",
     .desc = "ARM Versatile Express for Cortex-A9",
@@ -341,9 +473,18 @@ static QEMUMachine vexpress_a9_machine = {
     .max_cpus = 4,
 };
 
+static QEMUMachine vexpress_a15_machine = {
+    .name = "vexpress-a15",
+    .desc = "ARM Versatile Express for Cortex-A15",
+    .init = vexpress_a15_init,
+    .use_scsi = 1,
+    .max_cpus = 4,
+};
+
 static void vexpress_machine_init(void)
 {
     qemu_register_machine(&vexpress_a9_machine);
+    qemu_register_machine(&vexpress_a15_machine);
 }
 
 machine_init(vexpress_machine_init);
commit 96eacf641346bc1c432281575a265f6348a8f5c6
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Feb 16 09:56:09 2012 +0000

    arm_boot: Pass base address of GIC CPU interface, not whole GIC
    
    The arm_boot secondary boot loader code needs the address of
    the GIC CPU interface. Obtaining this from the base address
    of the private peripheral region was possible for A9 and 11MPcore,
    but the A15 puts the GIC CPU interface in a different place.
    So make boards pass in the GIC CPU interface address directly.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/arm-misc.h b/hw/arm-misc.h
index 5e5204b..306013a 100644
--- a/hw/arm-misc.h
+++ b/hw/arm-misc.h
@@ -37,7 +37,7 @@ struct arm_boot_info {
      */
     target_phys_addr_t smp_loader_start;
     target_phys_addr_t smp_bootreg_addr;
-    target_phys_addr_t smp_priv_base;
+    target_phys_addr_t gic_cpu_if_addr;
     int nb_cpus;
     int board_id;
     int (*atag_board)(const struct arm_boot_info *info, void *p);
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index 34a8739..2ef25ca 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -43,16 +43,16 @@ static uint32_t bootloader[] = {
  * location for the kernel secondary CPU entry point.
  */
 static uint32_t smpboot[] = {
-  0xe59f201c, /* ldr r2, privbase */
+  0xe59f201c, /* ldr r2, gic_cpu_if */
   0xe59f001c, /* ldr r0, startaddr */
   0xe3a01001, /* mov r1, #1 */
-  0xe5821100, /* str r1, [r2, #256] */
+  0xe5821000, /* str r1, [r2] */
   0xe320f003, /* wfi */
   0xe5901000, /* ldr     r1, [r0] */
   0xe1110001, /* tst     r1, r1 */
   0x0afffffb, /* beq     <wfi> */
   0xe12fff11, /* bx      r1 */
-  0,          /* privbase: Private memory region base address.  */
+  0,          /* gic_cpu_if: base address of GIC CPU interface */
   0           /* bootreg: Boot register address is held here */
 };
 
@@ -61,7 +61,7 @@ static void default_write_secondary(CPUState *env,
 {
     int n;
     smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
-    smpboot[ARRAY_SIZE(smpboot) - 2] = info->smp_priv_base;
+    smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr;
     for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
         smpboot[n] = tswap32(smpboot[n]);
     }
diff --git a/hw/exynos4_boards.c b/hw/exynos4_boards.c
index 329efbe..553a02b 100644
--- a/hw/exynos4_boards.c
+++ b/hw/exynos4_boards.c
@@ -112,7 +112,8 @@ static Exynos4210State *exynos4_boards_init_common(
     exynos4_board_binfo.kernel_filename = kernel_filename;
     exynos4_board_binfo.initrd_filename = initrd_filename;
     exynos4_board_binfo.kernel_cmdline = kernel_cmdline;
-    exynos4_board_binfo.smp_priv_base = EXYNOS4210_SMP_PRIVATE_BASE_ADDR;
+    exynos4_board_binfo.gic_cpu_if_addr =
+            EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100;
 
     PRINT_DEBUG("\n ram_size: %luMiB [0x%08lx]\n"
             " kernel_filename: %s\n"
diff --git a/hw/realview.c b/hw/realview.c
index bcf982f..ae1bbcd 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -222,21 +222,23 @@ static void realview_init(ram_addr_t ram_size,
     sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000);
 
     if (is_mpcore) {
+        target_phys_addr_t periphbase;
         dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore");
         qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
         qdev_init_nofail(dev);
         busdev = sysbus_from_qdev(dev);
         if (is_pb) {
-            realview_binfo.smp_priv_base = 0x1f000000;
+            periphbase = 0x1f000000;
         } else {
-            realview_binfo.smp_priv_base = 0x10100000;
+            periphbase = 0x10100000;
         }
-        sysbus_mmio_map(busdev, 0, realview_binfo.smp_priv_base);
+        sysbus_mmio_map(busdev, 0, periphbase);
         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);
+        sysbus_create_varargs("l2x0", periphbase + 0x2000, NULL);
+        /* Both A9 and 11MPCore put the GIC CPU i/f at base + 0x100 */
+        realview_binfo.gic_cpu_if_addr = periphbase + 0x100;
     } else {
         uint32_t gic_addr = is_pb ? 0x1e000000 : 0x10040000;
         /* For now just create the nIRQ GIC, and ignore the others.  */
diff --git a/hw/vexpress.c b/hw/vexpress.c
index 43ad206..aae9d81 100644
--- a/hw/vexpress.c
+++ b/hw/vexpress.c
@@ -115,6 +115,7 @@ typedef void DBoardInitFn(const VEDBoardInfo *daughterboard,
 struct VEDBoardInfo {
     const target_phys_addr_t *motherboard_map;
     target_phys_addr_t loader_start;
+    const target_phys_addr_t gic_cpu_if_addr;
     DBoardInitFn *init;
 };
 
@@ -175,8 +176,7 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
     qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
     qdev_init_nofail(dev);
     busdev = sysbus_from_qdev(dev);
-    vexpress_binfo.smp_priv_base = 0x1e000000;
-    sysbus_mmio_map(busdev, 0, vexpress_binfo.smp_priv_base);
+    sysbus_mmio_map(busdev, 0, 0x1e000000);
     for (n = 0; n < smp_cpus; n++) {
         sysbus_connect_irq(busdev, n, cpu_irq[n]);
     }
@@ -214,6 +214,7 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
 static const VEDBoardInfo a9_daughterboard = {
     .motherboard_map = motherboard_legacy_map,
     .loader_start = 0x60000000,
+    .gic_cpu_if_addr = 0x1e000100,
     .init = a9_daughterboard_init,
 };
 
@@ -316,6 +317,7 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard,
     vexpress_binfo.loader_start = daughterboard->loader_start;
     vexpress_binfo.smp_loader_start = map[VE_SRAM];
     vexpress_binfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
+    vexpress_binfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
     arm_load_kernel(first_cpu, &vexpress_binfo);
 }
 
commit b7206878680f1e77031dacb420ef2c630a6b6257
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Feb 16 09:56:09 2012 +0000

    hw/vexpress.c: Instantiate the motherboard CLCD
    
    Instantiate the CLCD on the vexpress motherboard as well as one on
    the daughterboard -- the A15 daughterboard does not have a CLCD
    and so relies on the motherboard one.
    
    At the moment QEMU doesn't provide infrastructure for selecting
    which display device gets to actually show graphics -- the first
    one registered is it. Fortunately this works for the major use
    case (Linux): if the daughterboard has a CLCD it will come first
    and be used, otherwise we fall back to the motherboard CLCD.
    So we don't (currently) need to implement the control register
    which allows software to tell the mux which video output to pass
    through to the outside world.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Andreas Färber <afaerber at suse.de>

diff --git a/hw/vexpress.c b/hw/vexpress.c
index 8239ea1..43ad206 100644
--- a/hw/vexpress.c
+++ b/hw/vexpress.c
@@ -282,7 +282,7 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard,
 
     /* VE_COMPACTFLASH: not modelled */
 
-    /* VE_CLCD: not modelled (we use the daughterboard CLCD only) */
+    sysbus_create_simple("pl111", map[VE_CLCD], pic[14]);
 
     /* VE_NORFLASH0: not modelled */
     /* VE_NORFLASH0ALIAS: not modelled */
commit 4c3b29b8ad22857b1bb8e28cb17eabd108d9b978
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Feb 16 09:56:09 2012 +0000

    hw/vexpress.c: Factor out daughterboard-specific initialization
    
    Factor out daughterboard specifics into a data structure and
    daughterboard initialization function, in preparation for adding
    vexpress-a15 support.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/vexpress.c b/hw/vexpress.c
index 6d8eee2..8239ea1 100644
--- a/hw/vexpress.c
+++ b/hw/vexpress.c
@@ -103,32 +103,43 @@ static target_phys_addr_t motherboard_legacy_map[] = {
     [VE_USB] = 0x4f000000,
 };
 
-static void vexpress_a9_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)
+/* Structure defining the peculiarities of a specific daughterboard */
+
+typedef struct VEDBoardInfo VEDBoardInfo;
+
+typedef void DBoardInitFn(const VEDBoardInfo *daughterboard,
+                          ram_addr_t ram_size,
+                          const char *cpu_model,
+                          qemu_irq *pic, uint32_t *proc_id);
+
+struct VEDBoardInfo {
+    const target_phys_addr_t *motherboard_map;
+    target_phys_addr_t loader_start;
+    DBoardInitFn *init;
+};
+
+static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
+                                  ram_addr_t ram_size,
+                                  const char *cpu_model,
+                                  qemu_irq *pic, uint32_t *proc_id)
 {
     CPUState *env = NULL;
     MemoryRegion *sysmem = get_system_memory();
     MemoryRegion *ram = g_new(MemoryRegion, 1);
     MemoryRegion *lowram = g_new(MemoryRegion, 1);
-    MemoryRegion *vram = g_new(MemoryRegion, 1);
-    MemoryRegion *sram = g_new(MemoryRegion, 1);
-    DeviceState *dev, *sysctl, *pl041;
+    DeviceState *dev;
     SysBusDevice *busdev;
     qemu_irq *irqp;
-    qemu_irq pic[64];
     int n;
     qemu_irq cpu_irq[4];
-    uint32_t proc_id;
-    uint32_t sys_id;
-    ram_addr_t low_ram_size, vram_size, sram_size;
-    target_phys_addr_t *map = motherboard_legacy_map;
+    ram_addr_t low_ram_size;
 
     if (!cpu_model) {
         cpu_model = "cortex-a9";
     }
 
+    *proc_id = 0x0c000191;
+
     for (n = 0; n < smp_cpus; n++) {
         env = cpu_init(cpu_model);
         if (!env) {
@@ -141,7 +152,7 @@ static void vexpress_a9_init(ram_addr_t ram_size,
 
     if (ram_size > 0x40000000) {
         /* 1GB is the maximum the address space permits */
-        fprintf(stderr, "vexpress: cannot model more than 1GB RAM\n");
+        fprintf(stderr, "vexpress-a9: cannot model more than 1GB RAM\n");
         exit(1);
     }
 
@@ -179,12 +190,58 @@ static void vexpress_a9_init(ram_addr_t ram_size,
         pic[n] = qdev_get_gpio_in(dev, n);
     }
 
+    /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
+
+    /* 0x10020000 PL111 CLCD (daughterboard) */
+    sysbus_create_simple("pl111", 0x10020000, pic[44]);
+
+    /* 0x10060000 AXI RAM */
+    /* 0x100e0000 PL341 Dynamic Memory Controller */
+    /* 0x100e1000 PL354 Static Memory Controller */
+    /* 0x100e2000 System Configuration Controller */
+
+    sysbus_create_simple("sp804", 0x100e4000, pic[48]);
+    /* 0x100e5000 SP805 Watchdog module */
+    /* 0x100e6000 BP147 TrustZone Protection Controller */
+    /* 0x100e9000 PL301 'Fast' AXI matrix */
+    /* 0x100ea000 PL301 'Slow' AXI matrix */
+    /* 0x100ec000 TrustZone Address Space Controller */
+    /* 0x10200000 CoreSight debug APB */
+    /* 0x1e00a000 PL310 L2 Cache Controller */
+    sysbus_create_varargs("l2x0", 0x1e00a000, NULL);
+}
+
+static const VEDBoardInfo a9_daughterboard = {
+    .motherboard_map = motherboard_legacy_map,
+    .loader_start = 0x60000000,
+    .init = a9_daughterboard_init,
+};
+
+static void vexpress_common_init(const VEDBoardInfo *daughterboard,
+                                 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)
+{
+    DeviceState *dev, *sysctl, *pl041;
+    qemu_irq pic[64];
+    uint32_t proc_id;
+    uint32_t sys_id;
+    ram_addr_t vram_size, sram_size;
+    MemoryRegion *sysmem = get_system_memory();
+    MemoryRegion *vram = g_new(MemoryRegion, 1);
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
+    const target_phys_addr_t *map = daughterboard->motherboard_map;
+
+    daughterboard->init(daughterboard, ram_size, cpu_model, pic, &proc_id);
+
     /* Motherboard peripherals: the wiring is the same but the
      * addresses vary between the legacy and A-Series memory maps.
      */
 
     sys_id = 0x1190f500;
-    proc_id = 0x0c000191;
 
     sysctl = qdev_create(NULL, "realview_sysctl");
     qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
@@ -227,26 +284,6 @@ static void vexpress_a9_init(ram_addr_t ram_size,
 
     /* VE_CLCD: not modelled (we use the daughterboard CLCD only) */
 
-    /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
-
-    /* 0x10020000 PL111 CLCD (daughterboard) */
-    sysbus_create_simple("pl111", 0x10020000, pic[44]);
-
-    /* 0x10060000 AXI RAM */
-    /* 0x100e0000 PL341 Dynamic Memory Controller */
-    /* 0x100e1000 PL354 Static Memory Controller */
-    /* 0x100e2000 System Configuration Controller */
-
-    sysbus_create_simple("sp804", 0x100e4000, pic[48]);
-    /* 0x100e5000 SP805 Watchdog module */
-    /* 0x100e6000 BP147 TrustZone Protection Controller */
-    /* 0x100e9000 PL301 'Fast' AXI matrix */
-    /* 0x100ea000 PL301 'Slow' AXI matrix */
-    /* 0x100ec000 TrustZone Address Space Controller */
-    /* 0x10200000 CoreSight debug APB */
-    /* 0x1e00a000 PL310 L2 Cache Controller */
-    sysbus_create_varargs("l2x0", 0x1e00a000, NULL);
-
     /* VE_NORFLASH0: not modelled */
     /* VE_NORFLASH0ALIAS: not modelled */
     /* VE_NORFLASH1: not modelled */
@@ -276,12 +313,23 @@ static void vexpress_a9_init(ram_addr_t ram_size,
     vexpress_binfo.initrd_filename = initrd_filename;
     vexpress_binfo.nb_cpus = smp_cpus;
     vexpress_binfo.board_id = VEXPRESS_BOARD_ID;
-    vexpress_binfo.loader_start = 0x60000000;
+    vexpress_binfo.loader_start = daughterboard->loader_start;
     vexpress_binfo.smp_loader_start = map[VE_SRAM];
     vexpress_binfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
     arm_load_kernel(first_cpu, &vexpress_binfo);
 }
 
+static void vexpress_a9_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)
+{
+    vexpress_common_init(&a9_daughterboard,
+                         ram_size, boot_device, kernel_filename,
+                         kernel_cmdline, initrd_filename, cpu_model);
+}
 
 static QEMUMachine vexpress_a9_machine = {
     .name = "vexpress-a9",
commit aac1e02c1d4b6d02f35a199a454fd46416380ff5
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Feb 16 09:56:08 2012 +0000

    hw/vexpress.c: Move secondary CPU boot code to SRAM
    
    On real Versatile Express hardware, the boot ROM puts the secondary
    CPU bootcode/holding pen in SRAM. We can therefore rely on Linux not
    trashing this memory until secondary CPUs have booted up, and can
    put our QEMU-specific pen code in the same place. This allows us to
    drop the odd "hack" RAM page we were using before.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/vexpress.c b/hw/vexpress.c
index 38ae05f..6d8eee2 100644
--- a/hw/vexpress.c
+++ b/hw/vexpress.c
@@ -30,13 +30,9 @@
 #include "boards.h"
 #include "exec-memory.h"
 
-#define SMP_BOOT_ADDR 0xe0000000
-
 #define VEXPRESS_BOARD_ID 0x8e0
 
-static struct arm_boot_info vexpress_binfo = {
-    .smp_loader_start = SMP_BOOT_ADDR,
-};
+static struct arm_boot_info vexpress_binfo;
 
 /* Address maps for peripherals:
  * the Versatile Express motherboard has two possible maps,
@@ -118,7 +114,6 @@ static void vexpress_a9_init(ram_addr_t ram_size,
     MemoryRegion *lowram = g_new(MemoryRegion, 1);
     MemoryRegion *vram = g_new(MemoryRegion, 1);
     MemoryRegion *sram = g_new(MemoryRegion, 1);
-    MemoryRegion *hackram = g_new(MemoryRegion, 1);
     DeviceState *dev, *sysctl, *pl041;
     SysBusDevice *busdev;
     qemu_irq *irqp;
@@ -275,14 +270,6 @@ static void vexpress_a9_init(ram_addr_t ram_size,
 
     /* VE_DAPROM: not modelled */
 
-    /* ??? Hack to map an additional page of ram for the secondary CPU
-       startup code.  I guess this works on real hardware because the
-       BootROM happens to be in ROM/flash or in memory that isn't clobbered
-       until after Linux boots the secondary CPUs.  */
-    memory_region_init_ram(hackram, "vexpress.hack", 0x1000);
-    vmstate_register_ram_global(hackram);
-    memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, hackram);
-
     vexpress_binfo.ram_size = ram_size;
     vexpress_binfo.kernel_filename = kernel_filename;
     vexpress_binfo.kernel_cmdline = kernel_cmdline;
@@ -290,6 +277,7 @@ static void vexpress_a9_init(ram_addr_t ram_size,
     vexpress_binfo.nb_cpus = smp_cpus;
     vexpress_binfo.board_id = VEXPRESS_BOARD_ID;
     vexpress_binfo.loader_start = 0x60000000;
+    vexpress_binfo.smp_loader_start = map[VE_SRAM];
     vexpress_binfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
     arm_load_kernel(first_cpu, &vexpress_binfo);
 }
commit 2558e0a67b5573cfd29c9346350ac5d5dc6f866f
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Feb 16 09:56:08 2012 +0000

    hw/vexpress.c: Make motherboard peripheral memory map table-driven
    
    Pull the addresses used for mapping motherboard peripherals into
    memory out into a table. This will allow us to simply provide a
    second table to implement the "Cortex-A Series" memory map used by
    the A15 variant of Versatile Express, as well as the current
    "Legacy" map used by A9.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Andreas Färber <afaerber at suse.de>

diff --git a/hw/vexpress.c b/hw/vexpress.c
index 43f47a6..38ae05f 100644
--- a/hw/vexpress.c
+++ b/hw/vexpress.c
@@ -31,13 +31,80 @@
 #include "exec-memory.h"
 
 #define SMP_BOOT_ADDR 0xe0000000
-#define SMP_BOOTREG_ADDR 0x10000030
 
 #define VEXPRESS_BOARD_ID 0x8e0
 
 static struct arm_boot_info vexpress_binfo = {
     .smp_loader_start = SMP_BOOT_ADDR,
-    .smp_bootreg_addr = SMP_BOOTREG_ADDR,
+};
+
+/* Address maps for peripherals:
+ * the Versatile Express motherboard has two possible maps,
+ * the "legacy" one (used for A9) and the "Cortex-A Series"
+ * map (used for newer cores).
+ * Individual daughterboards can also have different maps for
+ * their peripherals.
+ */
+
+enum {
+    VE_SYSREGS,
+    VE_SP810,
+    VE_SERIALPCI,
+    VE_PL041,
+    VE_MMCI,
+    VE_KMI0,
+    VE_KMI1,
+    VE_UART0,
+    VE_UART1,
+    VE_UART2,
+    VE_UART3,
+    VE_WDT,
+    VE_TIMER01,
+    VE_TIMER23,
+    VE_SERIALDVI,
+    VE_RTC,
+    VE_COMPACTFLASH,
+    VE_CLCD,
+    VE_NORFLASH0,
+    VE_NORFLASH0ALIAS,
+    VE_NORFLASH1,
+    VE_SRAM,
+    VE_VIDEORAM,
+    VE_ETHERNET,
+    VE_USB,
+    VE_DAPROM,
+};
+
+static target_phys_addr_t motherboard_legacy_map[] = {
+    /* CS7: 0x10000000 .. 0x10020000 */
+    [VE_SYSREGS] = 0x10000000,
+    [VE_SP810] = 0x10001000,
+    [VE_SERIALPCI] = 0x10002000,
+    [VE_PL041] = 0x10004000,
+    [VE_MMCI] = 0x10005000,
+    [VE_KMI0] = 0x10006000,
+    [VE_KMI1] = 0x10007000,
+    [VE_UART0] = 0x10009000,
+    [VE_UART1] = 0x1000a000,
+    [VE_UART2] = 0x1000b000,
+    [VE_UART3] = 0x1000c000,
+    [VE_WDT] = 0x1000f000,
+    [VE_TIMER01] = 0x10011000,
+    [VE_TIMER23] = 0x10012000,
+    [VE_SERIALDVI] = 0x10016000,
+    [VE_RTC] = 0x10017000,
+    [VE_COMPACTFLASH] = 0x1001a000,
+    [VE_CLCD] = 0x1001f000,
+    /* CS0: 0x40000000 .. 0x44000000 */
+    [VE_NORFLASH0] = 0x40000000,
+    /* CS1: 0x44000000 .. 0x48000000 */
+    [VE_NORFLASH1] = 0x44000000,
+    /* CS2: 0x48000000 .. 0x4a000000 */
+    [VE_SRAM] = 0x48000000,
+    /* CS3: 0x4c000000 .. 0x50000000 */
+    [VE_VIDEORAM] = 0x4c000000,
+    [VE_ETHERNET] = 0x4e000000,
+    [VE_USB] = 0x4f000000,
 };
 
 static void vexpress_a9_init(ram_addr_t ram_size,
@@ -61,6 +128,7 @@ static void vexpress_a9_init(ram_addr_t ram_size,
     uint32_t proc_id;
     uint32_t sys_id;
     ram_addr_t low_ram_size, vram_size, sram_size;
+    target_phys_addr_t *map = motherboard_legacy_map;
 
     if (!cpu_model) {
         cpu_model = "cortex-a9";
@@ -116,53 +184,53 @@ static void vexpress_a9_init(ram_addr_t ram_size,
         pic[n] = qdev_get_gpio_in(dev, n);
     }
 
-    /* Motherboard peripherals CS7 : 0x10000000 .. 0x10020000 */
+    /* Motherboard peripherals: the wiring is the same but the
+     * addresses vary between the legacy and A-Series memory maps.
+     */
+
     sys_id = 0x1190f500;
     proc_id = 0x0c000191;
 
-    /* 0x10000000 System registers */
     sysctl = qdev_create(NULL, "realview_sysctl");
     qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
     qdev_prop_set_uint32(sysctl, "proc_id", proc_id);
     qdev_init_nofail(sysctl);
-    sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000);
+    sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, map[VE_SYSREGS]);
+
+    /* VE_SP810: not modelled */
+    /* VE_SERIALPCI: not modelled */
 
-    /* 0x10001000 SP810 system control */
-    /* 0x10002000 serial bus PCI */
-    /* 0x10004000 PL041 audio */
     pl041 = qdev_create(NULL, "pl041");
     qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
     qdev_init_nofail(pl041);
-    sysbus_mmio_map(sysbus_from_qdev(pl041), 0, 0x10004000);
+    sysbus_mmio_map(sysbus_from_qdev(pl041), 0, map[VE_PL041]);
     sysbus_connect_irq(sysbus_from_qdev(pl041), 0, pic[11]);
 
-    dev = sysbus_create_varargs("pl181", 0x10005000, pic[9], pic[10], NULL);
+    dev = sysbus_create_varargs("pl181", map[VE_MMCI], pic[9], pic[10], NULL);
     /* Wire up MMC card detect and read-only signals */
     qdev_connect_gpio_out(dev, 0,
                           qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT));
     qdev_connect_gpio_out(dev, 1,
                           qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN));
 
-    sysbus_create_simple("pl050_keyboard", 0x10006000, pic[12]);
-    sysbus_create_simple("pl050_mouse", 0x10007000, pic[13]);
-
-    sysbus_create_simple("pl011", 0x10009000, pic[5]);
-    sysbus_create_simple("pl011", 0x1000a000, pic[6]);
-    sysbus_create_simple("pl011", 0x1000b000, pic[7]);
-    sysbus_create_simple("pl011", 0x1000c000, pic[8]);
+    sysbus_create_simple("pl050_keyboard", map[VE_KMI0], pic[12]);
+    sysbus_create_simple("pl050_mouse", map[VE_KMI1], pic[13]);
 
-    /* 0x1000f000 SP805 WDT */
+    sysbus_create_simple("pl011", map[VE_UART0], pic[5]);
+    sysbus_create_simple("pl011", map[VE_UART1], pic[6]);
+    sysbus_create_simple("pl011", map[VE_UART2], pic[7]);
+    sysbus_create_simple("pl011", map[VE_UART3], pic[8]);
 
-    sysbus_create_simple("sp804", 0x10011000, pic[2]);
-    sysbus_create_simple("sp804", 0x10012000, pic[3]);
+    sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]);
+    sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]);
 
-    /* 0x10016000 Serial Bus DVI */
+    /* VE_SERIALDVI: not modelled */
 
-    sysbus_create_simple("pl031", 0x10017000, pic[4]); /* RTC */
+    sysbus_create_simple("pl031", map[VE_RTC], pic[4]); /* RTC */
 
-    /* 0x1001a000 Compact Flash */
+    /* VE_COMPACTFLASH: not modelled */
 
-    /* 0x1001f000 PL111 CLCD (motherboard) */
+    /* VE_CLCD: not modelled (we use the daughterboard CLCD only) */
 
     /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
 
@@ -184,28 +252,28 @@ static void vexpress_a9_init(ram_addr_t ram_size,
     /* 0x1e00a000 PL310 L2 Cache Controller */
     sysbus_create_varargs("l2x0", 0x1e00a000, NULL);
 
-    /* CS0: NOR0 flash          : 0x40000000 .. 0x44000000 */
-    /* CS4: NOR1 flash          : 0x44000000 .. 0x48000000 */
-    /* CS2: SRAM                : 0x48000000 .. 0x4a000000 */
+    /* VE_NORFLASH0: not modelled */
+    /* VE_NORFLASH0ALIAS: not modelled */
+    /* VE_NORFLASH1: not modelled */
+
     sram_size = 0x2000000;
     memory_region_init_ram(sram, "vexpress.sram", sram_size);
     vmstate_register_ram_global(sram);
-    memory_region_add_subregion(sysmem, 0x48000000, sram);
-
-    /* CS3: USB, ethernet, VRAM : 0x4c000000 .. 0x50000000 */
+    memory_region_add_subregion(sysmem, map[VE_SRAM], sram);
 
-    /* 0x4c000000 Video RAM */
     vram_size = 0x800000;
     memory_region_init_ram(vram, "vexpress.vram", vram_size);
     vmstate_register_ram_global(vram);
-    memory_region_add_subregion(sysmem, 0x4c000000, vram);
+    memory_region_add_subregion(sysmem, map[VE_VIDEORAM], vram);
 
     /* 0x4e000000 LAN9118 Ethernet */
     if (nd_table[0].vlan) {
-        lan9118_init(&nd_table[0], 0x4e000000, pic[15]);
+        lan9118_init(&nd_table[0], map[VE_ETHERNET], pic[15]);
     }
 
-    /* 0x4f000000 ISP1761 USB */
+    /* VE_USB: not modelled */
+
+    /* VE_DAPROM: not modelled */
 
     /* ??? Hack to map an additional page of ram for the secondary CPU
        startup code.  I guess this works on real hardware because the
@@ -222,6 +290,7 @@ static void vexpress_a9_init(ram_addr_t ram_size,
     vexpress_binfo.nb_cpus = smp_cpus;
     vexpress_binfo.board_id = VEXPRESS_BOARD_ID;
     vexpress_binfo.loader_start = 0x60000000;
+    vexpress_binfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
     arm_load_kernel(first_cpu, &vexpress_binfo);
 }
 
commit 5d782e0805b4d216909b21883dcd513c3061aa3d
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Feb 16 09:56:07 2012 +0000

    hw/a15mpcore.c: Add Cortex-A15 private peripheral model
    
    Add a model of the Cortex-A15 memory mapped private peripheral
    space. This is fairly simple because the only memory mapped
    bit of the A15 is the GIC.
    
    Note that we don't currently model a VGIC and therefore don't
    map the VGIC related bits of the GIC.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/Makefile.target b/Makefile.target
index 2defdc4..651500e 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -348,7 +348,7 @@ obj-arm-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
 obj-arm-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
 obj-arm-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o
 obj-arm-y += arm_l2x0.o
-obj-arm-y += arm_mptimer.o
+obj-arm-y += arm_mptimer.o a15mpcore.o
 obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
 obj-arm-y += highbank.o
 obj-arm-y += pl061.o
diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c
new file mode 100644
index 0000000..71142e5
--- /dev/null
+++ b/hw/a15mpcore.c
@@ -0,0 +1,103 @@
+/*
+ * Cortex-A15MPCore internal peripheral emulation.
+ *
+ * Copyright (c) 2012 Linaro Limited.
+ * Written by Peter Maydell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 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"
+
+/* Configuration for arm_gic.c:
+ * max number of CPUs, how to ID current CPU
+ */
+#define NCPU 4
+
+static inline int gic_get_current_cpu(void)
+{
+  return cpu_single_env->cpu_index;
+}
+
+#include "arm_gic.c"
+
+/* A15MP private memory region.  */
+
+typedef struct A15MPPrivState {
+    gic_state gic;
+    uint32_t num_cpu;
+    uint32_t num_irq;
+    MemoryRegion container;
+} A15MPPrivState;
+
+static int a15mp_priv_init(SysBusDevice *dev)
+{
+    A15MPPrivState *s = FROM_SYSBUSGIC(A15MPPrivState, dev);
+
+    if (s->num_cpu > NCPU) {
+        hw_error("a15mp_priv_init: num-cpu may not be more than %d\n", NCPU);
+    }
+
+    gic_init(&s->gic, s->num_cpu, s->num_irq);
+
+    /* Memory map (addresses are offsets from PERIPHBASE):
+     *  0x0000-0x0fff -- reserved
+     *  0x1000-0x1fff -- GIC Distributor
+     *  0x2000-0x2fff -- GIC CPU interface
+     *  0x4000-0x4fff -- GIC virtual interface control (not modelled)
+     *  0x5000-0x5fff -- GIC virtual interface control (not modelled)
+     *  0x6000-0x7fff -- GIC virtual CPU interface (not modelled)
+     */
+    memory_region_init(&s->container, "a15mp-priv-container", 0x8000);
+    memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
+    memory_region_add_subregion(&s->container, 0x2000, &s->gic.cpuiomem[0]);
+
+    sysbus_init_mmio(dev, &s->container);
+    return 0;
+}
+
+static Property a15mp_priv_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", A15MPPrivState, num_cpu, 1),
+    /* The Cortex-A15MP 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-A15MP test chip in the
+     * Versatile Express A15 development board.
+     * Other boards may differ and should set this property appropriately.
+     */
+    DEFINE_PROP_UINT32("num-irq", A15MPPrivState, num_irq, 96),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void a15mp_priv_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    k->init = a15mp_priv_init;
+    dc->props = a15mp_priv_properties;
+    /* We currently have no savable state outside the common GIC state */
+}
+
+static TypeInfo a15mp_priv_info = {
+    .name  = "a15mpcore_priv",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(A15MPPrivState),
+    .class_init = a15mp_priv_class_init,
+};
+
+static void a15mp_register_types(void)
+{
+    type_register_static(&a15mp_priv_info);
+}
+
+type_init(a15mp_register_types)
commit fc63dcff46a2979ad998ff67c982f69d49691b7d
Author: Evgeny Voevodin <e.voevodin at samsung.com>
Date:   Thu Feb 16 09:56:06 2012 +0000

    MAINTAINERS: Add maintainers for Exynos SOC.
    
    Signed-off-by: Evgeny Voevodin <e.voevodin at samsung.com>
    Acked-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/MAINTAINERS b/MAINTAINERS
index 173e893..e55ea0f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -183,6 +183,14 @@ F: *win32*
 
 ARM Machines
 ------------
+Exynos
+M: Evgeny Voevodin <e.voevodin at samsung.com>
+M: Maksim Kozlov <m.kozlov at samsung.com>
+M: Igor Mitsyanko <i.mitsyanko at samsung.com>
+M: Dmitry Solodkiy <d.solodkiy at samsung.com>
+S: Maintained
+F: hw/exynos*
+
 Gumstix
 M: qemu-devel at nongnu.org
 S: Orphan
commit 30628cb12de2e35d87cb04194113341b6a8922b2
Author: Mitsyanko Igor <i.mitsyanko at samsung.com>
Date:   Thu Feb 16 09:56:06 2012 +0000

    Exynos4210: added display controller implementation
    
    Exynos4210 display controller (FIMD) has 5 hardware windows with alpha and
    chroma key blending functions.
    
    Signed-off-by: Mitsyanko Igor <i.mitsyanko at samsung.com>
    Signed-off-by: Evgeny Voevodin <e.voevodin at samsung.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/Makefile.target b/Makefile.target
index 6ceff54..2defdc4 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -346,7 +346,7 @@ obj-arm-y += versatile_pci.o
 obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
 obj-arm-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
 obj-arm-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
-obj-arm-y += exynos4210_pmu.o exynos4210_mct.o
+obj-arm-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o
 obj-arm-y += arm_l2x0.o
 obj-arm-y += arm_mptimer.o
 obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
diff --git a/hw/exynos4210.c b/hw/exynos4210.c
index 558f669..f904370 100644
--- a/hw/exynos4210.c
+++ b/hw/exynos4210.c
@@ -58,6 +58,9 @@
 /* PMU SFR base address */
 #define EXYNOS4210_PMU_BASE_ADDR            0x10020000
 
+/* Display controllers (FIMD) */
+#define EXYNOS4210_FIMD0_BASE_ADDR          0x11C00000
+
 static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43,
                                     0x09, 0x00, 0x00, 0x00 };
 
@@ -256,5 +259,12 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
                            EXYNOS4210_UART3_FIFO_SIZE, 3, NULL,
                   s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]);
 
+    /*** Display controller (FIMD) ***/
+    sysbus_create_varargs("exynos4210.fimd", EXYNOS4210_FIMD0_BASE_ADDR,
+            s->irq_table[exynos4210_get_irq(11, 0)],
+            s->irq_table[exynos4210_get_irq(11, 1)],
+            s->irq_table[exynos4210_get_irq(11, 2)],
+            NULL);
+
     return s;
 }
diff --git a/hw/exynos4210_fimd.c b/hw/exynos4210_fimd.c
new file mode 100644
index 0000000..3313f00
--- /dev/null
+++ b/hw/exynos4210_fimd.c
@@ -0,0 +1,1928 @@
+/*
+ * Samsung exynos4210 Display Controller (FIMD)
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ * All rights reserved.
+ * Based on LCD controller for Samsung S5PC1xx-based board emulation
+ * by Kirill Batuzov <batuzovk at ispras.ru>
+ *
+ * Contributed by Mitsyanko Igor <i.mitsyanko at samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program 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 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 "qemu-common.h"
+#include "cpu-all.h"
+#include "sysbus.h"
+#include "console.h"
+#include "pixel_ops.h"
+#include "bswap.h"
+
+/* Debug messages configuration */
+#define EXYNOS4210_FIMD_DEBUG              0
+#define EXYNOS4210_FIMD_MODE_TRACE         0
+
+#if EXYNOS4210_FIMD_DEBUG == 0
+    #define DPRINT_L1(fmt, args...)       do { } while (0)
+    #define DPRINT_L2(fmt, args...)       do { } while (0)
+    #define DPRINT_ERROR(fmt, args...)    do { } while (0)
+#elif EXYNOS4210_FIMD_DEBUG == 1
+    #define DPRINT_L1(fmt, args...) \
+        do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
+    #define DPRINT_L2(fmt, args...)       do { } while (0)
+    #define DPRINT_ERROR(fmt, args...)  \
+        do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
+#else
+    #define DPRINT_L1(fmt, args...) \
+        do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
+    #define DPRINT_L2(fmt, args...) \
+        do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
+    #define DPRINT_ERROR(fmt, args...)  \
+        do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
+#endif
+
+#if EXYNOS4210_FIMD_MODE_TRACE == 0
+    #define DPRINT_TRACE(fmt, args...)        do { } while (0)
+#else
+    #define DPRINT_TRACE(fmt, args...)        \
+        do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
+#endif
+
+#define NUM_OF_WINDOWS              5
+#define FIMD_REGS_SIZE              0x4114
+
+/* Video main control registers */
+#define FIMD_VIDCON0                0x0000
+#define FIMD_VIDCON1                0x0004
+#define FIMD_VIDCON2                0x0008
+#define FIMD_VIDCON3                0x000C
+#define FIMD_VIDCON0_ENVID_F        (1 << 0)
+#define FIMD_VIDCON0_ENVID          (1 << 1)
+#define FIMD_VIDCON0_ENVID_MASK     ((1 << 0) | (1 << 1))
+#define FIMD_VIDCON1_ROMASK         0x07FFE000
+
+/* Video time control registers */
+#define FIMD_VIDTCON_START          0x10
+#define FIMD_VIDTCON_END            0x1C
+#define FIMD_VIDTCON2_SIZE_MASK     0x07FF
+#define FIMD_VIDTCON2_HOR_SHIFT     0
+#define FIMD_VIDTCON2_VER_SHIFT     11
+
+/* Window control registers */
+#define FIMD_WINCON_START           0x0020
+#define FIMD_WINCON_END             0x0030
+#define FIMD_WINCON_ROMASK          0x82200000
+#define FIMD_WINCON_ENWIN           (1 << 0)
+#define FIMD_WINCON_BLD_PIX         (1 << 6)
+#define FIMD_WINCON_ALPHA_MUL       (1 << 7)
+#define FIMD_WINCON_ALPHA_SEL       (1 << 1)
+#define FIMD_WINCON_SWAP            0x078000
+#define FIMD_WINCON_SWAP_SHIFT      15
+#define FIMD_WINCON_SWAP_WORD       0x1
+#define FIMD_WINCON_SWAP_HWORD      0x2
+#define FIMD_WINCON_SWAP_BYTE       0x4
+#define FIMD_WINCON_SWAP_BITS       0x8
+#define FIMD_WINCON_BUFSTAT_L       (1 << 21)
+#define FIMD_WINCON_BUFSTAT_H       (1 << 31)
+#define FIMD_WINCON_BUFSTATUS       ((1 << 21) | (1 << 31))
+#define FIMD_WINCON_BUF0_STAT       ((0 << 21) | (0 << 31))
+#define FIMD_WINCON_BUF1_STAT       ((1 << 21) | (0 << 31))
+#define FIMD_WINCON_BUF2_STAT       ((0 << 21) | (1 << 31))
+#define FIMD_WINCON_BUFSELECT       ((1 << 20) | (1 << 30))
+#define FIMD_WINCON_BUF0_SEL        ((0 << 20) | (0 << 30))
+#define FIMD_WINCON_BUF1_SEL        ((1 << 20) | (0 << 30))
+#define FIMD_WINCON_BUF2_SEL        ((0 << 20) | (1 << 30))
+#define FIMD_WINCON_BUFMODE         (1 << 14)
+#define IS_PALETTIZED_MODE(w)       (w->wincon & 0xC)
+#define PAL_MODE_WITH_ALPHA(x)       ((x) == 7)
+#define WIN_BPP_MODE(w)             ((w->wincon >> 2) & 0xF)
+#define WIN_BPP_MODE_WITH_ALPHA(w)     \
+    (WIN_BPP_MODE(w) == 0xD || WIN_BPP_MODE(w) == 0xE)
+
+/* Shadow control register */
+#define FIMD_SHADOWCON              0x0034
+#define FIMD_WINDOW_PROTECTED(s, w) ((s) & (1 << (10 + (w))))
+/* Channel mapping control register */
+#define FIMD_WINCHMAP               0x003C
+
+/* Window position control registers */
+#define FIMD_VIDOSD_START           0x0040
+#define FIMD_VIDOSD_END             0x0088
+#define FIMD_VIDOSD_COORD_MASK      0x07FF
+#define FIMD_VIDOSD_HOR_SHIFT       11
+#define FIMD_VIDOSD_VER_SHIFT       0
+#define FIMD_VIDOSD_ALPHA_AEN0      0xFFF000
+#define FIMD_VIDOSD_AEN0_SHIFT      12
+#define FIMD_VIDOSD_ALPHA_AEN1      0x000FFF
+
+/* Frame buffer address registers */
+#define FIMD_VIDWADD0_START         0x00A0
+#define FIMD_VIDWADD0_END           0x00C4
+#define FIMD_VIDWADD0_END           0x00C4
+#define FIMD_VIDWADD1_START         0x00D0
+#define FIMD_VIDWADD1_END           0x00F4
+#define FIMD_VIDWADD2_START         0x0100
+#define FIMD_VIDWADD2_END           0x0110
+#define FIMD_VIDWADD2_PAGEWIDTH     0x1FFF
+#define FIMD_VIDWADD2_OFFSIZE       0x1FFF
+#define FIMD_VIDWADD2_OFFSIZE_SHIFT 13
+#define FIMD_VIDW0ADD0_B2           0x20A0
+#define FIMD_VIDW4ADD0_B2           0x20C0
+
+/* Video interrupt control registers */
+#define FIMD_VIDINTCON0             0x130
+#define FIMD_VIDINTCON1             0x134
+
+/* Window color key registers */
+#define FIMD_WKEYCON_START          0x140
+#define FIMD_WKEYCON_END            0x15C
+#define FIMD_WKEYCON0_COMPKEY       0x00FFFFFF
+#define FIMD_WKEYCON0_CTL_SHIFT     24
+#define FIMD_WKEYCON0_DIRCON        (1 << 24)
+#define FIMD_WKEYCON0_KEYEN         (1 << 25)
+#define FIMD_WKEYCON0_KEYBLEN       (1 << 26)
+/* Window color key alpha control register */
+#define FIMD_WKEYALPHA_START        0x160
+#define FIMD_WKEYALPHA_END          0x16C
+
+/* Dithering control register */
+#define FIMD_DITHMODE               0x170
+
+/* Window alpha control registers */
+#define FIMD_VIDALPHA_ALPHA_LOWER   0x000F0F0F
+#define FIMD_VIDALPHA_ALPHA_UPPER   0x00F0F0F0
+#define FIMD_VIDWALPHA_START        0x21C
+#define FIMD_VIDWALPHA_END          0x240
+
+/* Window color map registers */
+#define FIMD_WINMAP_START           0x180
+#define FIMD_WINMAP_END             0x190
+#define FIMD_WINMAP_EN              (1 << 24)
+#define FIMD_WINMAP_COLOR_MASK      0x00FFFFFF
+
+/* Window palette control registers */
+#define FIMD_WPALCON_HIGH           0x019C
+#define FIMD_WPALCON_LOW            0x01A0
+#define FIMD_WPALCON_UPDATEEN       (1 << 9)
+#define FIMD_WPAL_W0PAL_L           0x07
+#define FIMD_WPAL_W0PAL_L_SHT        0
+#define FIMD_WPAL_W1PAL_L           0x07
+#define FIMD_WPAL_W1PAL_L_SHT       3
+#define FIMD_WPAL_W2PAL_L           0x01
+#define FIMD_WPAL_W2PAL_L_SHT       6
+#define FIMD_WPAL_W2PAL_H           0x06
+#define FIMD_WPAL_W2PAL_H_SHT       8
+#define FIMD_WPAL_W3PAL_L           0x01
+#define FIMD_WPAL_W3PAL_L_SHT       7
+#define FIMD_WPAL_W3PAL_H           0x06
+#define FIMD_WPAL_W3PAL_H_SHT       12
+#define FIMD_WPAL_W4PAL_L           0x01
+#define FIMD_WPAL_W4PAL_L_SHT       8
+#define FIMD_WPAL_W4PAL_H           0x06
+#define FIMD_WPAL_W4PAL_H_SHT       16
+
+/* Trigger control registers */
+#define FIMD_TRIGCON                0x01A4
+#define FIMD_TRIGCON_ROMASK         0x00000004
+
+/* LCD I80 Interface Control */
+#define FIMD_I80IFCON_START         0x01B0
+#define FIMD_I80IFCON_END           0x01BC
+/* Color gain control register */
+#define FIMD_COLORGAINCON           0x01C0
+/* LCD i80 Interface Command Control */
+#define FIMD_LDI_CMDCON0            0x01D0
+#define FIMD_LDI_CMDCON1            0x01D4
+/* I80 System Interface Manual Command Control */
+#define FIMD_SIFCCON0               0x01E0
+#define FIMD_SIFCCON2               0x01E8
+
+/* Hue Control Registers */
+#define FIMD_HUECOEFCR_START        0x01EC
+#define FIMD_HUECOEFCR_END          0x01F4
+#define FIMD_HUECOEFCB_START        0x01FC
+#define FIMD_HUECOEFCB_END          0x0208
+#define FIMD_HUEOFFSET              0x020C
+
+/* Video interrupt control registers */
+#define FIMD_VIDINT_INTFIFOPEND     (1 << 0)
+#define FIMD_VIDINT_INTFRMPEND      (1 << 1)
+#define FIMD_VIDINT_INTI80PEND      (1 << 2)
+#define FIMD_VIDINT_INTEN           (1 << 0)
+#define FIMD_VIDINT_INTFIFOEN       (1 << 1)
+#define FIMD_VIDINT_INTFRMEN        (1 << 12)
+#define FIMD_VIDINT_I80IFDONE       (1 << 17)
+
+/* Window blend equation control registers */
+#define FIMD_BLENDEQ_START          0x0244
+#define FIMD_BLENDEQ_END            0x0250
+#define FIMD_BLENDCON               0x0260
+#define FIMD_ALPHA_8BIT             (1 << 0)
+#define FIMD_BLENDEQ_COEF_MASK      0xF
+
+/* Window RTQOS Control Registers */
+#define FIMD_WRTQOSCON_START        0x0264
+#define FIMD_WRTQOSCON_END          0x0274
+
+/* LCD I80 Interface Command */
+#define FIMD_I80IFCMD_START         0x0280
+#define FIMD_I80IFCMD_END           0x02AC
+
+/* Shadow windows control registers */
+#define FIMD_SHD_ADD0_START         0x40A0
+#define FIMD_SHD_ADD0_END           0x40C0
+#define FIMD_SHD_ADD1_START         0x40D0
+#define FIMD_SHD_ADD1_END           0x40F0
+#define FIMD_SHD_ADD2_START         0x4100
+#define FIMD_SHD_ADD2_END           0x4110
+
+/* Palette memory */
+#define FIMD_PAL_MEM_START          0x2400
+#define FIMD_PAL_MEM_END            0x37FC
+/* Palette memory aliases for windows 0 and 1 */
+#define FIMD_PALMEM_AL_START        0x0400
+#define FIMD_PALMEM_AL_END          0x0BFC
+
+typedef struct {
+    uint8_t r, g, b;
+    /* D[31..24]dummy, D[23..16]rAlpha, D[15..8]gAlpha, D[7..0]bAlpha */
+    uint32_t a;
+} rgba;
+#define RGBA_SIZE  7
+
+typedef void pixel_to_rgb_func(uint32_t pixel, rgba *p);
+typedef struct Exynos4210fimdWindow Exynos4210fimdWindow;
+
+struct Exynos4210fimdWindow {
+    uint32_t wincon;        /* Window control register */
+    uint32_t buf_start[3];  /* Start address for video frame buffer */
+    uint32_t buf_end[3];    /* End address for video frame buffer */
+    uint32_t keycon[2];     /* Window color key registers */
+    uint32_t keyalpha;      /* Color key alpha control register */
+    uint32_t winmap;        /* Window color map register */
+    uint32_t blendeq;       /* Window blending equation control register */
+    uint32_t rtqoscon;      /* Window RTQOS Control Registers */
+    uint32_t palette[256];  /* Palette RAM */
+    uint32_t shadow_buf_start;      /* Start address of shadow frame buffer */
+    uint32_t shadow_buf_end;        /* End address of shadow frame buffer */
+    uint32_t shadow_buf_size;       /* Virtual shadow screen width */
+
+    pixel_to_rgb_func *pixel_to_rgb;
+    void (*draw_line)(Exynos4210fimdWindow *w, uint8_t *src, uint8_t *dst,
+            bool blend);
+    uint32_t (*get_alpha)(Exynos4210fimdWindow *w, uint32_t pix_a);
+    uint16_t lefttop_x, lefttop_y;   /* VIDOSD0 register */
+    uint16_t rightbot_x, rightbot_y; /* VIDOSD1 register */
+    uint32_t osdsize;                /* VIDOSD2&3 register */
+    uint32_t alpha_val[2];           /* VIDOSD2&3, VIDWALPHA registers */
+    uint16_t virtpage_width;         /* VIDWADD2 register */
+    uint16_t virtpage_offsize;       /* VIDWADD2 register */
+    MemoryRegionSection mem_section; /* RAM fragment containing framebuffer */
+    uint8_t *host_fb_addr;           /* Host pointer to window's framebuffer */
+    target_phys_addr_t fb_len;       /* Framebuffer length */
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    DisplayState *console;
+    qemu_irq irq[3];
+
+    uint32_t vidcon[4];     /* Video main control registers 0-3 */
+    uint32_t vidtcon[4];    /* Video time control registers 0-3 */
+    uint32_t shadowcon;     /* Window shadow control register */
+    uint32_t winchmap;      /* Channel mapping control register */
+    uint32_t vidintcon[2];  /* Video interrupt control registers */
+    uint32_t dithmode;      /* Dithering control register */
+    uint32_t wpalcon[2];    /* Window palette control registers */
+    uint32_t trigcon;       /* Trigger control register */
+    uint32_t i80ifcon[4];   /* I80 interface control registers */
+    uint32_t colorgaincon;  /* Color gain control register */
+    uint32_t ldi_cmdcon[2]; /* LCD I80 interface command control */
+    uint32_t sifccon[3];    /* I80 System Interface Manual Command Control */
+    uint32_t huecoef_cr[4]; /* Hue control registers */
+    uint32_t huecoef_cb[4]; /* Hue control registers */
+    uint32_t hueoffset;     /* Hue offset control register */
+    uint32_t blendcon;      /* Blending control register */
+    uint32_t i80ifcmd[12];  /* LCD I80 Interface Command */
+
+    Exynos4210fimdWindow window[5];    /* Window-specific registers */
+    uint8_t *ifb;           /* Internal frame buffer */
+    bool invalidate;        /* Image needs to be redrawn */
+    bool enabled;           /* Display controller is enabled */
+} Exynos4210fimdState;
+
+/* Perform byte/halfword/word swap of data according to WINCON */
+static inline void fimd_swap_data(unsigned int swap_ctl, uint64_t *data)
+{
+    int i;
+    uint64_t res;
+    uint64_t x = *data;
+
+    if (swap_ctl & FIMD_WINCON_SWAP_BITS) {
+        res = 0;
+        for (i = 0; i < 64; i++) {
+            if (x & (1ULL << (64 - i))) {
+                res |= (1ULL << i);
+            }
+        }
+        x = res;
+    }
+
+    if (swap_ctl & FIMD_WINCON_SWAP_BYTE) {
+        x = bswap64(x);
+    }
+
+    if (swap_ctl & FIMD_WINCON_SWAP_HWORD) {
+        x = ((x & 0x000000000000FFFFULL) << 48) |
+            ((x & 0x00000000FFFF0000ULL) << 16) |
+            ((x & 0x0000FFFF00000000ULL) >> 16) |
+            ((x & 0xFFFF000000000000ULL) >> 48);
+    }
+
+    if (swap_ctl & FIMD_WINCON_SWAP_WORD) {
+        x = ((x & 0x00000000FFFFFFFFULL) << 32) |
+            ((x & 0xFFFFFFFF00000000ULL) >> 32);
+    }
+
+    *data = x;
+}
+
+/* Conversion routines of Pixel data from frame buffer area to internal RGBA
+ * pixel representation.
+ * Every color component internally represented as 8-bit value. If original
+ * data has less than 8 bit for component, data is extended to 8 bit. For
+ * example, if blue component has only two possible values 0 and 1 it will be
+ * extended to 0 and 0xFF */
+
+/* One bit for alpha representation */
+#define DEF_PIXEL_TO_RGB_A1(N, R, G, B) \
+static void N(uint32_t pixel, rgba *p) \
+{ \
+    p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
+           ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
+    pixel >>= (B); \
+    p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
+           ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
+    pixel >>= (G); \
+    p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
+           ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
+    pixel >>= (R); \
+    p->a = (pixel & 0x1); \
+}
+
+DEF_PIXEL_TO_RGB_A1(pixel_a444_to_rgb, 4, 4, 4)
+DEF_PIXEL_TO_RGB_A1(pixel_a555_to_rgb, 5, 5, 5)
+DEF_PIXEL_TO_RGB_A1(pixel_a666_to_rgb, 6, 6, 6)
+DEF_PIXEL_TO_RGB_A1(pixel_a665_to_rgb, 6, 6, 5)
+DEF_PIXEL_TO_RGB_A1(pixel_a888_to_rgb, 8, 8, 8)
+DEF_PIXEL_TO_RGB_A1(pixel_a887_to_rgb, 8, 8, 7)
+
+/* Alpha component is always zero */
+#define DEF_PIXEL_TO_RGB_A0(N, R, G, B) \
+static void N(uint32_t pixel, rgba *p) \
+{ \
+    p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
+           ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
+    pixel >>= (B); \
+    p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
+           ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
+    pixel >>= (G); \
+    p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
+           ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
+    p->a = 0x0; \
+}
+
+DEF_PIXEL_TO_RGB_A0(pixel_565_to_rgb,  5, 6, 5)
+DEF_PIXEL_TO_RGB_A0(pixel_555_to_rgb,  5, 5, 5)
+DEF_PIXEL_TO_RGB_A0(pixel_666_to_rgb,  6, 6, 6)
+DEF_PIXEL_TO_RGB_A0(pixel_888_to_rgb,  8, 8, 8)
+
+/* Alpha component has some meaningful value */
+#define DEF_PIXEL_TO_RGB_A(N, R, G, B, A) \
+static void N(uint32_t pixel, rgba *p) \
+{ \
+    p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
+           ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
+    pixel >>= (B); \
+    p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
+           ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
+    pixel >>= (G); \
+    p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
+           ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
+    pixel >>= (R); \
+    p->a = (pixel & ((1 << (A)) - 1)) << (8 - (A)) | \
+           ((pixel >> (2 * (A) - 8)) & ((1 << (8 - (A))) - 1)); \
+    p->a = p->a | (p->a << 8) | (p->a << 16); \
+}
+
+DEF_PIXEL_TO_RGB_A(pixel_4444_to_rgb, 4, 4, 4, 4)
+DEF_PIXEL_TO_RGB_A(pixel_8888_to_rgb, 8, 8, 8, 8)
+
+/* Lookup table to extent 2-bit color component to 8 bit */
+static const uint8_t pixel_lutable_2b[4] = {
+     0x0, 0x55, 0xAA, 0xFF
+};
+/* Lookup table to extent 3-bit color component to 8 bit */
+static const uint8_t pixel_lutable_3b[8] = {
+     0x0, 0x24, 0x49, 0x6D, 0x92, 0xB6, 0xDB, 0xFF
+};
+/* Special case for a232 bpp mode */
+static void pixel_a232_to_rgb(uint32_t pixel, rgba *p)
+{
+    p->b = pixel_lutable_2b[(pixel & 0x3)];
+    pixel >>= 2;
+    p->g = pixel_lutable_3b[(pixel & 0x7)];
+    pixel >>= 3;
+    p->r = pixel_lutable_2b[(pixel & 0x3)];
+    pixel >>= 2;
+    p->a = (pixel & 0x1);
+}
+
+/* Special case for (5+1, 5+1, 5+1) mode. Data bit 15 is common LSB
+ * for all three color components */
+static void pixel_1555_to_rgb(uint32_t pixel, rgba *p)
+{
+    uint8_t comm = (pixel >> 15) & 1;
+    p->b = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
+    pixel >>= 5;
+    p->g = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
+    pixel >>= 5;
+    p->r = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
+    p->a = 0x0;
+}
+
+/* Put/get pixel to/from internal LCD Controller framebuffer */
+
+static int put_pixel_ifb(const rgba p, uint8_t *d)
+{
+    *(uint8_t *)d++ = p.r;
+    *(uint8_t *)d++ = p.g;
+    *(uint8_t *)d++ = p.b;
+    *(uint32_t *)d = p.a;
+    return RGBA_SIZE;
+}
+
+static int get_pixel_ifb(const uint8_t *s, rgba *p)
+{
+    p->r = *(uint8_t *)s++;
+    p->g = *(uint8_t *)s++;
+    p->b = *(uint8_t *)s++;
+    p->a = (*(uint32_t *)s) & 0x00FFFFFF;
+    return RGBA_SIZE;
+}
+
+static pixel_to_rgb_func *palette_data_format[8] = {
+    [0] = pixel_565_to_rgb,
+    [1] = pixel_a555_to_rgb,
+    [2] = pixel_666_to_rgb,
+    [3] = pixel_a665_to_rgb,
+    [4] = pixel_a666_to_rgb,
+    [5] = pixel_888_to_rgb,
+    [6] = pixel_a888_to_rgb,
+    [7] = pixel_8888_to_rgb
+};
+
+/* Returns Index in palette data formats table for given window number WINDOW */
+static uint32_t
+exynos4210_fimd_palette_format(Exynos4210fimdState *s, int window)
+{
+    uint32_t ret;
+
+    switch (window) {
+    case 0:
+        ret = (s->wpalcon[1] >> FIMD_WPAL_W0PAL_L_SHT) & FIMD_WPAL_W0PAL_L;
+        if (ret != 7) {
+            ret = 6 - ret;
+        }
+        break;
+    case 1:
+        ret = (s->wpalcon[1] >> FIMD_WPAL_W1PAL_L_SHT) & FIMD_WPAL_W1PAL_L;
+        if (ret != 7) {
+            ret = 6 - ret;
+        }
+        break;
+    case 2:
+        ret = ((s->wpalcon[0] >> FIMD_WPAL_W2PAL_H_SHT) & FIMD_WPAL_W2PAL_H) |
+            ((s->wpalcon[1] >> FIMD_WPAL_W2PAL_L_SHT) & FIMD_WPAL_W2PAL_L);
+        break;
+    case 3:
+        ret = ((s->wpalcon[0] >> FIMD_WPAL_W3PAL_H_SHT) & FIMD_WPAL_W3PAL_H) |
+            ((s->wpalcon[1] >> FIMD_WPAL_W3PAL_L_SHT) & FIMD_WPAL_W3PAL_L);
+        break;
+    case 4:
+        ret = ((s->wpalcon[0] >> FIMD_WPAL_W4PAL_H_SHT) & FIMD_WPAL_W4PAL_H) |
+            ((s->wpalcon[1] >> FIMD_WPAL_W4PAL_L_SHT) & FIMD_WPAL_W4PAL_L);
+        break;
+    default:
+        hw_error("exynos4210.fimd: incorrect window number %d\n", window);
+        ret = 0;
+        break;
+    }
+    return ret;
+}
+
+#define FIMD_1_MINUS_COLOR(x)    \
+            ((0xFF - ((x) & 0xFF)) | (0xFF00 - ((x) & 0xFF00)) | \
+                                  (0xFF0000 - ((x) & 0xFF0000)))
+#define EXTEND_LOWER_HALFBYTE(x) (((x) & 0xF0F0F) | (((x) << 4) & 0xF0F0F0))
+#define EXTEND_UPPER_HALFBYTE(x) (((x) & 0xF0F0F0) | (((x) >> 4) & 0xF0F0F))
+
+/* Multiply three lower bytes of two 32-bit words with each other.
+ * Each byte with values 0-255 is considered as a number with possible values
+ * in a range [0 - 1] */
+static inline uint32_t fimd_mult_each_byte(uint32_t a, uint32_t b)
+{
+    uint32_t tmp;
+    uint32_t ret;
+
+    ret = ((tmp = (((a & 0xFF) * (b & 0xFF)) / 0xFF)) > 0xFF) ? 0xFF : tmp;
+    ret |= ((tmp = ((((a >> 8) & 0xFF) * ((b >> 8) & 0xFF)) / 0xFF)) > 0xFF) ?
+            0xFF00 : tmp << 8;
+    ret |= ((tmp = ((((a >> 16) & 0xFF) * ((b >> 16) & 0xFF)) / 0xFF)) > 0xFF) ?
+            0xFF0000 : tmp << 16;
+    return ret;
+}
+
+/* For each corresponding bytes of two 32-bit words: (a*b + c*d)
+ * Byte values 0-255 are mapped to a range [0 .. 1] */
+static inline uint32_t
+fimd_mult_and_sum_each_byte(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
+{
+    uint32_t tmp;
+    uint32_t ret;
+
+    ret = ((tmp = (((a & 0xFF) * (b & 0xFF) + (c & 0xFF) * (d & 0xFF)) / 0xFF))
+            > 0xFF) ? 0xFF : tmp;
+    ret |= ((tmp = ((((a >> 8) & 0xFF) * ((b >> 8) & 0xFF) + ((c >> 8) & 0xFF) *
+            ((d >> 8) & 0xFF)) / 0xFF)) > 0xFF) ? 0xFF00 : tmp << 8;
+    ret |= ((tmp = ((((a >> 16) & 0xFF) * ((b >> 16) & 0xFF) +
+            ((c >> 16) & 0xFF) * ((d >> 16) & 0xFF)) / 0xFF)) > 0xFF) ?
+                    0xFF0000 : tmp << 16;
+    return ret;
+}
+
+/* These routines cover all possible sources of window's transparent factor
+ * used in blending equation. Choice of routine is affected by WPALCON
+ * registers, BLENDCON register and window's WINCON register */
+
+static uint32_t fimd_get_alpha_pix(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return pix_a;
+}
+
+static uint32_t
+fimd_get_alpha_pix_extlow(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return EXTEND_LOWER_HALFBYTE(pix_a);
+}
+
+static uint32_t
+fimd_get_alpha_pix_exthigh(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return EXTEND_UPPER_HALFBYTE(pix_a);
+}
+
+static uint32_t fimd_get_alpha_mult(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return fimd_mult_each_byte(pix_a, w->alpha_val[0]);
+}
+
+static uint32_t fimd_get_alpha_mult_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return fimd_mult_each_byte(EXTEND_LOWER_HALFBYTE(pix_a),
+            EXTEND_UPPER_HALFBYTE(w->alpha_val[0]));
+}
+
+static uint32_t fimd_get_alpha_aen(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return w->alpha_val[pix_a];
+}
+
+static uint32_t fimd_get_alpha_aen_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return EXTEND_UPPER_HALFBYTE(w->alpha_val[pix_a]);
+}
+
+static uint32_t fimd_get_alpha_sel(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return w->alpha_val[(w->wincon & FIMD_WINCON_ALPHA_SEL) ? 1 : 0];
+}
+
+static uint32_t fimd_get_alpha_sel_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return EXTEND_UPPER_HALFBYTE(w->alpha_val[(w->wincon &
+            FIMD_WINCON_ALPHA_SEL) ? 1 : 0]);
+}
+
+/* Updates currently active alpha value get function for specified window */
+static void fimd_update_get_alpha(Exynos4210fimdState *s, int win)
+{
+    Exynos4210fimdWindow *w = &s->window[win];
+    const bool alpha_is_8bit = s->blendcon & FIMD_ALPHA_8BIT;
+
+    if (w->wincon & FIMD_WINCON_BLD_PIX) {
+        if ((w->wincon & FIMD_WINCON_ALPHA_SEL) && WIN_BPP_MODE_WITH_ALPHA(w)) {
+            /* In this case, alpha component contains meaningful value */
+            if (w->wincon & FIMD_WINCON_ALPHA_MUL) {
+                w->get_alpha = alpha_is_8bit ?
+                        fimd_get_alpha_mult : fimd_get_alpha_mult_ext;
+            } else {
+                w->get_alpha = alpha_is_8bit ?
+                        fimd_get_alpha_pix : fimd_get_alpha_pix_extlow;
+            }
+        } else {
+            if (IS_PALETTIZED_MODE(w) &&
+                  PAL_MODE_WITH_ALPHA(exynos4210_fimd_palette_format(s, win))) {
+                /* Alpha component has 8-bit numeric value */
+                w->get_alpha = alpha_is_8bit ?
+                        fimd_get_alpha_pix : fimd_get_alpha_pix_exthigh;
+            } else {
+                /* Alpha has only two possible values (AEN) */
+                w->get_alpha = alpha_is_8bit ?
+                        fimd_get_alpha_aen : fimd_get_alpha_aen_ext;
+            }
+        }
+    } else {
+        w->get_alpha = alpha_is_8bit ? fimd_get_alpha_sel :
+                fimd_get_alpha_sel_ext;
+    }
+}
+
+/* Blends current window's (w) pixel (foreground pixel *ret) with background
+ * window (w_blend) pixel p_bg according to formula:
+ * NEW_COLOR = a_coef x FG_PIXEL_COLOR + b_coef x BG_PIXEL_COLOR
+ * NEW_ALPHA = p_coef x FG_ALPHA + q_coef x BG_ALPHA
+ */
+static void
+exynos4210_fimd_blend_pixel(Exynos4210fimdWindow *w, rgba p_bg, rgba *ret)
+{
+    rgba p_fg = *ret;
+    uint32_t bg_color = ((p_bg.r & 0xFF) << 16) | ((p_bg.g & 0xFF) << 8) |
+            (p_bg.b & 0xFF);
+    uint32_t fg_color = ((p_fg.r & 0xFF) << 16) | ((p_fg.g & 0xFF) << 8) |
+            (p_fg.b & 0xFF);
+    uint32_t alpha_fg = p_fg.a;
+    int i;
+    /* It is possible that blending equation parameters a and b do not
+     * depend on window BLENEQ register. Account for this with first_coef */
+    enum { A_COEF = 0, B_COEF = 1, P_COEF = 2, Q_COEF = 3, COEF_NUM = 4};
+    uint32_t first_coef = A_COEF;
+    uint32_t blend_param[COEF_NUM];
+
+    if (w->keycon[0] & FIMD_WKEYCON0_KEYEN) {
+        uint32_t colorkey = (w->keycon[1] &
+              ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) & FIMD_WKEYCON0_COMPKEY;
+
+        if ((w->keycon[0] & FIMD_WKEYCON0_DIRCON) &&
+            (bg_color & ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) == colorkey) {
+            /* Foreground pixel is displayed */
+            if (w->keycon[0] & FIMD_WKEYCON0_KEYBLEN) {
+                alpha_fg = w->keyalpha;
+                blend_param[A_COEF] = alpha_fg;
+                blend_param[B_COEF] = FIMD_1_MINUS_COLOR(alpha_fg);
+            } else {
+                alpha_fg = 0;
+                blend_param[A_COEF] = 0xFFFFFF;
+                blend_param[B_COEF] = 0x0;
+            }
+            first_coef = P_COEF;
+        } else if ((w->keycon[0] & FIMD_WKEYCON0_DIRCON) == 0 &&
+            (fg_color & ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) == colorkey) {
+            /* Background pixel is displayed */
+            if (w->keycon[0] & FIMD_WKEYCON0_KEYBLEN) {
+                alpha_fg = w->keyalpha;
+                blend_param[A_COEF] = alpha_fg;
+                blend_param[B_COEF] = FIMD_1_MINUS_COLOR(alpha_fg);
+            } else {
+                alpha_fg = 0;
+                blend_param[A_COEF] = 0x0;
+                blend_param[B_COEF] = 0xFFFFFF;
+            }
+            first_coef = P_COEF;
+        }
+    }
+
+    for (i = first_coef; i < COEF_NUM; i++) {
+        switch ((w->blendeq >> i * 6) & FIMD_BLENDEQ_COEF_MASK) {
+        case 0:
+            blend_param[i] = 0;
+            break;
+        case 1:
+            blend_param[i] = 0xFFFFFF;
+            break;
+        case 2:
+            blend_param[i] = alpha_fg;
+            break;
+        case 3:
+            blend_param[i] = FIMD_1_MINUS_COLOR(alpha_fg);
+            break;
+        case 4:
+            blend_param[i] = p_bg.a;
+            break;
+        case 5:
+            blend_param[i] = FIMD_1_MINUS_COLOR(p_bg.a);
+            break;
+        case 6:
+            blend_param[i] = w->alpha_val[0];
+            break;
+        case 10:
+            blend_param[i] = fg_color;
+            break;
+        case 11:
+            blend_param[i] = FIMD_1_MINUS_COLOR(fg_color);
+            break;
+        case 12:
+            blend_param[i] = bg_color;
+            break;
+        case 13:
+            blend_param[i] = FIMD_1_MINUS_COLOR(bg_color);
+            break;
+        default:
+            hw_error("exynos4210.fimd: blend equation coef illegal value\n");
+            break;
+        }
+    }
+
+    fg_color = fimd_mult_and_sum_each_byte(bg_color, blend_param[B_COEF],
+            fg_color, blend_param[A_COEF]);
+    ret->b = fg_color & 0xFF;
+    fg_color >>= 8;
+    ret->g = fg_color & 0xFF;
+    fg_color >>= 8;
+    ret->r = fg_color & 0xFF;
+    ret->a = fimd_mult_and_sum_each_byte(alpha_fg, blend_param[P_COEF],
+            p_bg.a, blend_param[Q_COEF]);
+}
+
+/* These routines read data from video frame buffer in system RAM, convert
+ * this data to display controller internal representation, if necessary,
+ * perform pixel blending with data, currently presented in internal buffer.
+ * Result is stored in display controller internal frame buffer. */
+
+/* Draw line with index in palette table in RAM frame buffer data */
+#define DEF_DRAW_LINE_PALETTE(N) \
+static void glue(draw_line_palette_, N)(Exynos4210fimdWindow *w, uint8_t *src, \
+               uint8_t *dst, bool blend) \
+{ \
+    int width = w->rightbot_x - w->lefttop_x + 1; \
+    uint8_t *ifb = dst; \
+    uint8_t swap = (w->wincon & FIMD_WINCON_SWAP) >> FIMD_WINCON_SWAP_SHIFT; \
+    uint64_t data; \
+    rgba p, p_old; \
+    int i; \
+    do { \
+        data = ldq_raw((void *)src); \
+        src += 8; \
+        fimd_swap_data(swap, &data); \
+        for (i = (64 / (N) - 1); i >= 0; i--) { \
+            w->pixel_to_rgb(w->palette[(data >> ((N) * i)) & \
+                                   ((1ULL << (N)) - 1)], &p); \
+            p.a = w->get_alpha(w, p.a); \
+            if (blend) { \
+                ifb +=  get_pixel_ifb(ifb, &p_old); \
+                exynos4210_fimd_blend_pixel(w, p_old, &p); \
+            } \
+            dst += put_pixel_ifb(p, dst); \
+        } \
+        width -= (64 / (N)); \
+    } while (width > 0); \
+}
+
+/* Draw line with direct color value in RAM frame buffer data */
+#define DEF_DRAW_LINE_NOPALETTE(N) \
+static void glue(draw_line_, N)(Exynos4210fimdWindow *w, uint8_t *src, \
+                    uint8_t *dst, bool blend) \
+{ \
+    int width = w->rightbot_x - w->lefttop_x + 1; \
+    uint8_t *ifb = dst; \
+    uint8_t swap = (w->wincon & FIMD_WINCON_SWAP) >> FIMD_WINCON_SWAP_SHIFT; \
+    uint64_t data; \
+    rgba p, p_old; \
+    int i; \
+    do { \
+        data = ldq_raw((void *)src); \
+        src += 8; \
+        fimd_swap_data(swap, &data); \
+        for (i = (64 / (N) - 1); i >= 0; i--) { \
+            w->pixel_to_rgb((data >> ((N) * i)) & ((1ULL << (N)) - 1), &p); \
+            p.a = w->get_alpha(w, p.a); \
+            if (blend) { \
+                ifb += get_pixel_ifb(ifb, &p_old); \
+                exynos4210_fimd_blend_pixel(w, p_old, &p); \
+            } \
+            dst += put_pixel_ifb(p, dst); \
+        } \
+        width -= (64 / (N)); \
+    } while (width > 0); \
+}
+
+DEF_DRAW_LINE_PALETTE(1)
+DEF_DRAW_LINE_PALETTE(2)
+DEF_DRAW_LINE_PALETTE(4)
+DEF_DRAW_LINE_PALETTE(8)
+DEF_DRAW_LINE_NOPALETTE(8)  /* 8bpp mode has palette and non-palette versions */
+DEF_DRAW_LINE_NOPALETTE(16)
+DEF_DRAW_LINE_NOPALETTE(32)
+
+/* Special draw line routine for window color map case */
+static void draw_line_mapcolor(Exynos4210fimdWindow *w, uint8_t *src,
+                       uint8_t *dst, bool blend)
+{
+    rgba p, p_old;
+    uint8_t *ifb = dst;
+    int width = w->rightbot_x - w->lefttop_x + 1;
+    uint32_t map_color = w->winmap & FIMD_WINMAP_COLOR_MASK;
+
+    do {
+        pixel_888_to_rgb(map_color, &p);
+        p.a = w->get_alpha(w, p.a);
+        if (blend) {
+            ifb += get_pixel_ifb(ifb, &p_old);
+            exynos4210_fimd_blend_pixel(w, p_old, &p);
+        }
+        dst += put_pixel_ifb(p, dst);
+    } while (--width);
+}
+
+/* Write RGB to QEMU's GraphicConsole framebuffer */
+
+static int put_to_qemufb_pixel8(const rgba p, uint8_t *d)
+{
+    uint32_t pixel = rgb_to_pixel8(p.r, p.g, p.b);
+    *(uint8_t *)d = pixel;
+    return 1;
+}
+
+static int put_to_qemufb_pixel15(const rgba p, uint8_t *d)
+{
+    uint32_t pixel = rgb_to_pixel15(p.r, p.g, p.b);
+    *(uint16_t *)d = pixel;
+    return 2;
+}
+
+static int put_to_qemufb_pixel16(const rgba p, uint8_t *d)
+{
+    uint32_t pixel = rgb_to_pixel16(p.r, p.g, p.b);
+    *(uint16_t *)d = pixel;
+    return 2;
+}
+
+static int put_to_qemufb_pixel24(const rgba p, uint8_t *d)
+{
+    uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b);
+    *(uint8_t *)d++ = (pixel >>  0) & 0xFF;
+    *(uint8_t *)d++ = (pixel >>  8) & 0xFF;
+    *(uint8_t *)d++ = (pixel >> 16) & 0xFF;
+    return 3;
+}
+
+static int put_to_qemufb_pixel32(const rgba p, uint8_t *d)
+{
+    uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b);
+    *(uint32_t *)d = pixel;
+    return 4;
+}
+
+/* Routine to copy pixel from internal buffer to QEMU buffer */
+static int (*put_pixel_toqemu)(const rgba p, uint8_t *pixel);
+static inline void fimd_update_putpix_qemu(int bpp)
+{
+    switch (bpp) {
+    case 8:
+        put_pixel_toqemu = put_to_qemufb_pixel8;
+        break;
+    case 15:
+        put_pixel_toqemu = put_to_qemufb_pixel15;
+        break;
+    case 16:
+        put_pixel_toqemu = put_to_qemufb_pixel16;
+        break;
+    case 24:
+        put_pixel_toqemu = put_to_qemufb_pixel24;
+        break;
+    case 32:
+        put_pixel_toqemu = put_to_qemufb_pixel32;
+        break;
+    default:
+        hw_error("exynos4210.fimd: unsupported BPP (%d)", bpp);
+        break;
+    }
+}
+
+/* Routine to copy a line from internal frame buffer to QEMU display */
+static void fimd_copy_line_toqemu(int width, uint8_t *src, uint8_t *dst)
+{
+    rgba p;
+
+    do {
+        src += get_pixel_ifb(src, &p);
+        dst += put_pixel_toqemu(p, dst);
+    } while (--width);
+}
+
+/* Parse BPPMODE_F = WINCON1[5:2] bits */
+static void exynos4210_fimd_update_win_bppmode(Exynos4210fimdState *s, int win)
+{
+    Exynos4210fimdWindow *w = &s->window[win];
+
+    if (w->winmap & FIMD_WINMAP_EN) {
+        w->draw_line = draw_line_mapcolor;
+        return;
+    }
+
+    switch (WIN_BPP_MODE(w)) {
+    case 0:
+        w->draw_line = draw_line_palette_1;
+        w->pixel_to_rgb =
+                palette_data_format[exynos4210_fimd_palette_format(s, win)];
+        break;
+    case 1:
+        w->draw_line = draw_line_palette_2;
+        w->pixel_to_rgb =
+                palette_data_format[exynos4210_fimd_palette_format(s, win)];
+        break;
+    case 2:
+        w->draw_line = draw_line_palette_4;
+        w->pixel_to_rgb =
+                palette_data_format[exynos4210_fimd_palette_format(s, win)];
+        break;
+    case 3:
+        w->draw_line = draw_line_palette_8;
+        w->pixel_to_rgb =
+                palette_data_format[exynos4210_fimd_palette_format(s, win)];
+        break;
+    case 4:
+        w->draw_line = draw_line_8;
+        w->pixel_to_rgb = pixel_a232_to_rgb;
+        break;
+    case 5:
+        w->draw_line = draw_line_16;
+        w->pixel_to_rgb = pixel_565_to_rgb;
+        break;
+    case 6:
+        w->draw_line = draw_line_16;
+        w->pixel_to_rgb = pixel_a555_to_rgb;
+        break;
+    case 7:
+        w->draw_line = draw_line_16;
+        w->pixel_to_rgb = pixel_1555_to_rgb;
+        break;
+    case 8:
+        w->draw_line = draw_line_32;
+        w->pixel_to_rgb = pixel_666_to_rgb;
+        break;
+    case 9:
+        w->draw_line = draw_line_32;
+        w->pixel_to_rgb = pixel_a665_to_rgb;
+        break;
+    case 10:
+        w->draw_line = draw_line_32;
+        w->pixel_to_rgb = pixel_a666_to_rgb;
+        break;
+    case 11:
+        w->draw_line = draw_line_32;
+        w->pixel_to_rgb = pixel_888_to_rgb;
+        break;
+    case 12:
+        w->draw_line = draw_line_32;
+        w->pixel_to_rgb = pixel_a887_to_rgb;
+        break;
+    case 13:
+        w->draw_line = draw_line_32;
+        if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon &
+                FIMD_WINCON_ALPHA_SEL)) {
+            w->pixel_to_rgb = pixel_8888_to_rgb;
+        } else {
+            w->pixel_to_rgb = pixel_a888_to_rgb;
+        }
+        break;
+    case 14:
+        w->draw_line = draw_line_16;
+        if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon &
+                FIMD_WINCON_ALPHA_SEL)) {
+            w->pixel_to_rgb = pixel_4444_to_rgb;
+        } else {
+            w->pixel_to_rgb = pixel_a444_to_rgb;
+        }
+        break;
+    case 15:
+        w->draw_line = draw_line_16;
+        w->pixel_to_rgb = pixel_555_to_rgb;
+        break;
+    }
+}
+
+#if EXYNOS4210_FIMD_MODE_TRACE > 0
+static const char *exynos4210_fimd_get_bppmode(int mode_code)
+{
+    switch (mode_code) {
+    case 0:
+        return "1 bpp";
+    case 1:
+        return "2 bpp";
+    case 2:
+        return "4 bpp";
+    case 3:
+        return "8 bpp (palettized)";
+    case 4:
+        return "8 bpp (non-palettized, A: 1-R:2-G:3-B:2)";
+    case 5:
+        return "16 bpp (non-palettized, R:5-G:6-B:5)";
+    case 6:
+        return "16 bpp (non-palettized, A:1-R:5-G:5-B:5)";
+    case 7:
+        return "16 bpp (non-palettized, I :1-R:5-G:5-B:5)";
+    case 8:
+        return "Unpacked 18 bpp (non-palettized, R:6-G:6-B:6)";
+    case 9:
+        return "Unpacked 18bpp (non-palettized,A:1-R:6-G:6-B:5)";
+    case 10:
+        return "Unpacked 19bpp (non-palettized,A:1-R:6-G:6-B:6)";
+    case 11:
+        return "Unpacked 24 bpp (non-palettized R:8-G:8-B:8)";
+    case 12:
+        return "Unpacked 24 bpp (non-palettized A:1-R:8-G:8-B:7)";
+    case 13:
+        return "Unpacked 25 bpp (non-palettized A:1-R:8-G:8-B:8)";
+    case 14:
+        return "Unpacked 13 bpp (non-palettized A:1-R:4-G:4-B:4)";
+    case 15:
+        return "Unpacked 15 bpp (non-palettized R:5-G:5-B:5)";
+    default:
+        return "Non-existing bpp mode";
+    }
+}
+
+static inline void exynos4210_fimd_trace_bppmode(Exynos4210fimdState *s,
+                int win_num, uint32_t val)
+{
+    Exynos4210fimdWindow *w = &s->window[win_num];
+
+    if (w->winmap & FIMD_WINMAP_EN) {
+        printf("QEMU FIMD: Window %d is mapped with MAPCOLOR=0x%x\n",
+                win_num, w->winmap & 0xFFFFFF);
+        return;
+    }
+
+    if ((val != 0xFFFFFFFF) && ((w->wincon >> 2) & 0xF) == ((val >> 2) & 0xF)) {
+        return;
+    }
+    printf("QEMU FIMD: Window %d BPP mode set to %s\n", win_num,
+        exynos4210_fimd_get_bppmode((val >> 2) & 0xF));
+}
+#else
+static inline void exynos4210_fimd_trace_bppmode(Exynos4210fimdState *s,
+        int win_num, uint32_t val)
+{
+
+}
+#endif
+
+static inline int fimd_get_buffer_id(Exynos4210fimdWindow *w)
+{
+    switch (w->wincon & FIMD_WINCON_BUFSTATUS) {
+    case FIMD_WINCON_BUF0_STAT:
+        return 0;
+    case FIMD_WINCON_BUF1_STAT:
+        return 1;
+    case FIMD_WINCON_BUF2_STAT:
+        return 2;
+    default:
+        DPRINT_ERROR("Non-existent buffer index\n");
+        return 0;
+    }
+}
+
+/* Updates specified window's MemorySection based on values of WINCON,
+ * VIDOSDA, VIDOSDB, VIDWADDx and SHADOWCON registers */
+static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win)
+{
+    Exynos4210fimdWindow *w = &s->window[win];
+    target_phys_addr_t fb_start_addr, fb_mapped_len;
+
+    if (!s->enabled || !(w->wincon & FIMD_WINCON_ENWIN) ||
+            FIMD_WINDOW_PROTECTED(s->shadowcon, win)) {
+        return;
+    }
+
+    if (w->host_fb_addr) {
+        cpu_physical_memory_unmap(w->host_fb_addr, w->fb_len, 0, 0);
+        w->host_fb_addr = NULL;
+        w->fb_len = 0;
+    }
+
+    fb_start_addr = w->buf_start[fimd_get_buffer_id(w)];
+    /* Total number of bytes of virtual screen used by current window */
+    w->fb_len = fb_mapped_len = (w->virtpage_width + w->virtpage_offsize) *
+            (w->rightbot_y - w->lefttop_y + 1);
+    w->mem_section = memory_region_find(sysbus_address_space(&s->busdev),
+            fb_start_addr, w->fb_len);
+    assert(w->mem_section.mr);
+    assert(w->mem_section.offset_within_address_space == fb_start_addr);
+    DPRINT_TRACE("Window %u framebuffer changed: address=0x%08x, len=0x%x\n",
+            win, fb_start_addr, w->fb_len);
+
+    if (w->mem_section.size != w->fb_len ||
+            !memory_region_is_ram(w->mem_section.mr)) {
+        DPRINT_ERROR("Failed to find window %u framebuffer region\n", win);
+        goto error_return;
+    }
+
+    w->host_fb_addr = cpu_physical_memory_map(fb_start_addr, &fb_mapped_len, 0);
+    if (!w->host_fb_addr) {
+        DPRINT_ERROR("Failed to map window %u framebuffer\n", win);
+        goto error_return;
+    }
+
+    if (fb_mapped_len != w->fb_len) {
+        DPRINT_ERROR("Window %u mapped framebuffer length is less then "
+                "expected\n", win);
+        cpu_physical_memory_unmap(w->host_fb_addr, fb_mapped_len, 0, 0);
+        goto error_return;
+    }
+    return;
+
+error_return:
+    w->mem_section.mr = NULL;
+    w->mem_section.size = 0;
+    w->host_fb_addr = NULL;
+    w->fb_len = 0;
+}
+
+static void exynos4210_fimd_enable(Exynos4210fimdState *s, bool enabled)
+{
+    if (enabled && !s->enabled) {
+        unsigned w;
+        s->enabled = true;
+        for (w = 0; w < NUM_OF_WINDOWS; w++) {
+            fimd_update_memory_section(s, w);
+        }
+    }
+    s->enabled = enabled;
+    DPRINT_TRACE("display controller %s\n", enabled ? "enabled" : "disabled");
+}
+
+static inline uint32_t unpack_upper_4(uint32_t x)
+{
+    return ((x & 0xF00) << 12) | ((x & 0xF0) << 8) | ((x & 0xF) << 4);
+}
+
+static inline uint32_t pack_upper_4(uint32_t x)
+{
+    return (((x & 0xF00000) >> 12) | ((x & 0xF000) >> 8) |
+            ((x & 0xF0) >> 4)) & 0xFFF;
+}
+
+static void exynos4210_fimd_update_irq(Exynos4210fimdState *s)
+{
+    if (!(s->vidintcon[0] & FIMD_VIDINT_INTEN)) {
+        qemu_irq_lower(s->irq[0]);
+        qemu_irq_lower(s->irq[1]);
+        qemu_irq_lower(s->irq[2]);
+        return;
+    }
+    if ((s->vidintcon[0] & FIMD_VIDINT_INTFIFOEN) &&
+            (s->vidintcon[1] & FIMD_VIDINT_INTFIFOPEND)) {
+        qemu_irq_raise(s->irq[0]);
+    } else {
+        qemu_irq_lower(s->irq[0]);
+    }
+    if ((s->vidintcon[0] & FIMD_VIDINT_INTFRMEN) &&
+            (s->vidintcon[1] & FIMD_VIDINT_INTFRMPEND)) {
+        qemu_irq_raise(s->irq[1]);
+    } else {
+        qemu_irq_lower(s->irq[1]);
+    }
+    if ((s->vidintcon[0] & FIMD_VIDINT_I80IFDONE) &&
+            (s->vidintcon[1] & FIMD_VIDINT_INTI80PEND)) {
+        qemu_irq_raise(s->irq[2]);
+    } else {
+        qemu_irq_lower(s->irq[2]);
+    }
+}
+
+static void exynos4210_fimd_invalidate(void *opaque)
+{
+    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
+    s->invalidate = true;
+}
+
+static void exynos4210_update_resolution(Exynos4210fimdState *s)
+{
+    /* LCD resolution is stored in VIDEO TIME CONTROL REGISTER 2 */
+    uint32_t width = ((s->vidtcon[2] >> FIMD_VIDTCON2_HOR_SHIFT) &
+            FIMD_VIDTCON2_SIZE_MASK) + 1;
+    uint32_t height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) &
+            FIMD_VIDTCON2_SIZE_MASK) + 1;
+
+    if (s->ifb == NULL || ds_get_width(s->console) != width ||
+            ds_get_height(s->console) != height) {
+        DPRINT_L1("Resolution changed from %ux%u to %ux%u\n",
+           ds_get_width(s->console), ds_get_height(s->console), width, height);
+        qemu_console_resize(s->console, width, height);
+        s->ifb = g_realloc(s->ifb, width * height * RGBA_SIZE + 1);
+        memset(s->ifb, 0, width * height * RGBA_SIZE + 1);
+        exynos4210_fimd_invalidate(s);
+    }
+}
+
+static void exynos4210_fimd_update(void *opaque)
+{
+    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
+    Exynos4210fimdWindow *w;
+    int i, line;
+    target_phys_addr_t fb_line_addr, inc_size;
+    int scrn_height;
+    int first_line = -1, last_line = -1, scrn_width;
+    bool blend = false;
+    uint8_t *host_fb_addr;
+    bool is_dirty = false;
+    const int global_width = (s->vidtcon[2] & FIMD_VIDTCON2_SIZE_MASK) + 1;
+    const int global_height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) &
+            FIMD_VIDTCON2_SIZE_MASK) + 1;
+
+    if (!s || !s->console || !ds_get_bits_per_pixel(s->console) ||
+            !s->enabled) {
+        return;
+    }
+    exynos4210_update_resolution(s);
+
+    for (i = 0; i < NUM_OF_WINDOWS; i++) {
+        w = &s->window[i];
+        if ((w->wincon & FIMD_WINCON_ENWIN) && w->host_fb_addr) {
+            scrn_height = w->rightbot_y - w->lefttop_y + 1;
+            scrn_width = w->virtpage_width;
+            /* Total width of virtual screen page in bytes */
+            inc_size = scrn_width + w->virtpage_offsize;
+            memory_region_sync_dirty_bitmap(w->mem_section.mr);
+            host_fb_addr = w->host_fb_addr;
+            fb_line_addr = w->mem_section.offset_within_region;
+
+            for (line = 0; line < scrn_height; line++) {
+                is_dirty = memory_region_get_dirty(w->mem_section.mr,
+                            fb_line_addr, scrn_width, DIRTY_MEMORY_VGA);
+
+                if (s->invalidate || is_dirty) {
+                    if (first_line == -1) {
+                        first_line = line;
+                    }
+                    last_line = line;
+                    w->draw_line(w, host_fb_addr, s->ifb +
+                        w->lefttop_x * RGBA_SIZE + (w->lefttop_y + line) *
+                        global_width * RGBA_SIZE, blend);
+                }
+                host_fb_addr += inc_size;
+                fb_line_addr += inc_size;
+                is_dirty = false;
+            }
+            memory_region_reset_dirty(w->mem_section.mr,
+                w->mem_section.offset_within_region,
+                w->fb_len, DIRTY_MEMORY_VGA);
+            blend = true;
+        }
+    }
+
+    /* Copy resulting image to QEMU_CONSOLE. */
+    if (first_line >= 0) {
+        uint8_t *d;
+        int bpp;
+
+        bpp = ds_get_bits_per_pixel(s->console);
+        fimd_update_putpix_qemu(bpp);
+        bpp = (bpp + 1) >> 3;
+        d = ds_get_data(s->console);
+        for (line = first_line; line <= last_line; line++) {
+            fimd_copy_line_toqemu(global_width, s->ifb + global_width * line *
+                    RGBA_SIZE, d + global_width * line * bpp);
+        }
+        dpy_update(s->console, 0, 0, global_width, global_height);
+    }
+    s->invalidate = false;
+    s->vidintcon[1] |= FIMD_VIDINT_INTFRMPEND;
+    if ((s->vidcon[0] & FIMD_VIDCON0_ENVID_F) == 0) {
+        exynos4210_fimd_enable(s, false);
+    }
+    exynos4210_fimd_update_irq(s);
+}
+
+static void exynos4210_fimd_reset(DeviceState *d)
+{
+    Exynos4210fimdState *s = DO_UPCAST(Exynos4210fimdState, busdev.qdev, d);
+    unsigned w;
+
+    DPRINT_TRACE("Display controller reset\n");
+    /* Set all display controller registers to 0 */
+    memset(&s->vidcon, 0, (uint8_t *)&s->window - (uint8_t *)&s->vidcon);
+    for (w = 0; w < NUM_OF_WINDOWS; w++) {
+        memset(&s->window[w], 0, sizeof(Exynos4210fimdWindow));
+        s->window[w].blendeq = 0xC2;
+        exynos4210_fimd_update_win_bppmode(s, w);
+        exynos4210_fimd_trace_bppmode(s, w, 0xFFFFFFFF);
+        fimd_update_get_alpha(s, w);
+    }
+
+    if (s->ifb != NULL) {
+        g_free(s->ifb);
+    }
+    s->ifb = NULL;
+
+    exynos4210_fimd_invalidate(s);
+    exynos4210_fimd_enable(s, false);
+    /* Some registers have non-zero initial values */
+    s->winchmap = 0x7D517D51;
+    s->colorgaincon = 0x10040100;
+    s->huecoef_cr[0] = s->huecoef_cr[3] = 0x01000100;
+    s->huecoef_cb[0] = s->huecoef_cb[3] = 0x01000100;
+    s->hueoffset = 0x01800080;
+}
+
+static void exynos4210_fimd_write(void *opaque, target_phys_addr_t offset,
+                              uint64_t val, unsigned size)
+{
+    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
+    unsigned w, i;
+    uint32_t old_value;
+
+    DPRINT_L2("write offset 0x%08x, value=%llu(0x%08llx)\n", offset,
+            (long long unsigned int)val, (long long unsigned int)val);
+
+    switch (offset) {
+    case FIMD_VIDCON0:
+        if ((val & FIMD_VIDCON0_ENVID_MASK) == FIMD_VIDCON0_ENVID_MASK) {
+            exynos4210_fimd_enable(s, true);
+        } else {
+            if ((val & FIMD_VIDCON0_ENVID) == 0) {
+                exynos4210_fimd_enable(s, false);
+            }
+        }
+        s->vidcon[0] = val;
+        break;
+    case FIMD_VIDCON1:
+        /* Leave read-only bits as is */
+        val = (val & (~FIMD_VIDCON1_ROMASK)) |
+                (s->vidcon[1] & FIMD_VIDCON1_ROMASK);
+        s->vidcon[1] = val;
+        break;
+    case FIMD_VIDCON2 ... FIMD_VIDCON3:
+        s->vidcon[(offset) >> 2] = val;
+        break;
+    case FIMD_VIDTCON_START ... FIMD_VIDTCON_END:
+        s->vidtcon[(offset - FIMD_VIDTCON_START) >> 2] = val;
+        break;
+    case FIMD_WINCON_START ... FIMD_WINCON_END:
+        w = (offset - FIMD_WINCON_START) >> 2;
+        /* Window's current buffer ID */
+        i = fimd_get_buffer_id(&s->window[w]);
+        old_value = s->window[w].wincon;
+        val = (val & ~FIMD_WINCON_ROMASK) |
+                (s->window[w].wincon & FIMD_WINCON_ROMASK);
+        if (w == 0) {
+            /* Window 0 wincon ALPHA_MUL bit must always be 0 */
+            val &= ~FIMD_WINCON_ALPHA_MUL;
+        }
+        exynos4210_fimd_trace_bppmode(s, w, val);
+        switch (val & FIMD_WINCON_BUFSELECT) {
+        case FIMD_WINCON_BUF0_SEL:
+            val &= ~FIMD_WINCON_BUFSTATUS;
+            break;
+        case FIMD_WINCON_BUF1_SEL:
+            val = (val & ~FIMD_WINCON_BUFSTAT_H) | FIMD_WINCON_BUFSTAT_L;
+            break;
+        case FIMD_WINCON_BUF2_SEL:
+            if (val & FIMD_WINCON_BUFMODE) {
+                val = (val & ~FIMD_WINCON_BUFSTAT_L) | FIMD_WINCON_BUFSTAT_H;
+            }
+            break;
+        default:
+            break;
+        }
+        s->window[w].wincon = val;
+        exynos4210_fimd_update_win_bppmode(s, w);
+        fimd_update_get_alpha(s, w);
+        if ((i != fimd_get_buffer_id(&s->window[w])) ||
+                (!(old_value & FIMD_WINCON_ENWIN) && (s->window[w].wincon &
+                        FIMD_WINCON_ENWIN))) {
+            fimd_update_memory_section(s, w);
+        }
+        break;
+    case FIMD_SHADOWCON:
+        old_value = s->shadowcon;
+        s->shadowcon = val;
+        for (w = 0; w < NUM_OF_WINDOWS; w++) {
+            if (FIMD_WINDOW_PROTECTED(old_value, w) &&
+                    !FIMD_WINDOW_PROTECTED(s->shadowcon, w)) {
+                fimd_update_memory_section(s, w);
+            }
+        }
+        break;
+    case FIMD_WINCHMAP:
+        s->winchmap = val;
+        break;
+    case FIMD_VIDOSD_START ... FIMD_VIDOSD_END:
+        w = (offset - FIMD_VIDOSD_START) >> 4;
+        i = ((offset - FIMD_VIDOSD_START) & 0xF) >> 2;
+        switch (i) {
+        case 0:
+            old_value = s->window[w].lefttop_y;
+            s->window[w].lefttop_x = (val >> FIMD_VIDOSD_HOR_SHIFT) &
+                                      FIMD_VIDOSD_COORD_MASK;
+            s->window[w].lefttop_y = (val >> FIMD_VIDOSD_VER_SHIFT) &
+                                      FIMD_VIDOSD_COORD_MASK;
+            if (s->window[w].lefttop_y != old_value) {
+                fimd_update_memory_section(s, w);
+            }
+            break;
+        case 1:
+            old_value = s->window[w].rightbot_y;
+            s->window[w].rightbot_x = (val >> FIMD_VIDOSD_HOR_SHIFT) &
+                                       FIMD_VIDOSD_COORD_MASK;
+            s->window[w].rightbot_y = (val >> FIMD_VIDOSD_VER_SHIFT) &
+                                       FIMD_VIDOSD_COORD_MASK;
+            if (s->window[w].rightbot_y != old_value) {
+                fimd_update_memory_section(s, w);
+            }
+            break;
+        case 2:
+            if (w == 0) {
+                s->window[w].osdsize = val;
+            } else {
+                s->window[w].alpha_val[0] =
+                    unpack_upper_4((val & FIMD_VIDOSD_ALPHA_AEN0) >>
+                    FIMD_VIDOSD_AEN0_SHIFT) |
+                    (s->window[w].alpha_val[0] & FIMD_VIDALPHA_ALPHA_LOWER);
+                s->window[w].alpha_val[1] =
+                    unpack_upper_4(val & FIMD_VIDOSD_ALPHA_AEN1) |
+                    (s->window[w].alpha_val[1] & FIMD_VIDALPHA_ALPHA_LOWER);
+            }
+            break;
+        case 3:
+            if (w != 1 && w != 2) {
+                DPRINT_ERROR("Bad write offset 0x%08x\n", offset);
+                return;
+            }
+            s->window[w].osdsize = val;
+            break;
+        }
+        break;
+    case FIMD_VIDWADD0_START ... FIMD_VIDWADD0_END:
+        w = (offset - FIMD_VIDWADD0_START) >> 3;
+        i = ((offset - FIMD_VIDWADD0_START) >> 2) & 1;
+        if (i == fimd_get_buffer_id(&s->window[w]) &&
+                s->window[w].buf_start[i] != val) {
+            s->window[w].buf_start[i] = val;
+            fimd_update_memory_section(s, w);
+            break;
+        }
+        s->window[w].buf_start[i] = val;
+        break;
+    case FIMD_VIDWADD1_START ... FIMD_VIDWADD1_END:
+        w = (offset - FIMD_VIDWADD1_START) >> 3;
+        i = ((offset - FIMD_VIDWADD1_START) >> 2) & 1;
+        s->window[w].buf_end[i] = val;
+        break;
+    case FIMD_VIDWADD2_START ... FIMD_VIDWADD2_END:
+        w = (offset - FIMD_VIDWADD2_START) >> 2;
+        if (((val & FIMD_VIDWADD2_PAGEWIDTH) != s->window[w].virtpage_width) ||
+            (((val >> FIMD_VIDWADD2_OFFSIZE_SHIFT) & FIMD_VIDWADD2_OFFSIZE) !=
+                        s->window[w].virtpage_offsize)) {
+            s->window[w].virtpage_width = val & FIMD_VIDWADD2_PAGEWIDTH;
+            s->window[w].virtpage_offsize =
+                (val >> FIMD_VIDWADD2_OFFSIZE_SHIFT) & FIMD_VIDWADD2_OFFSIZE;
+            fimd_update_memory_section(s, w);
+        }
+        break;
+    case FIMD_VIDINTCON0:
+        s->vidintcon[0] = val;
+        break;
+    case FIMD_VIDINTCON1:
+        s->vidintcon[1] &= ~(val & 7);
+        exynos4210_fimd_update_irq(s);
+        break;
+    case FIMD_WKEYCON_START ... FIMD_WKEYCON_END:
+        w = ((offset - FIMD_WKEYCON_START) >> 3) + 1;
+        i = ((offset - FIMD_WKEYCON_START) >> 2) & 1;
+        s->window[w].keycon[i] = val;
+        break;
+    case FIMD_WKEYALPHA_START ... FIMD_WKEYALPHA_END:
+        w = ((offset - FIMD_WKEYALPHA_START) >> 2) + 1;
+        s->window[w].keyalpha = val;
+        break;
+    case FIMD_DITHMODE:
+        s->dithmode = val;
+        break;
+    case FIMD_WINMAP_START ... FIMD_WINMAP_END:
+        w = (offset - FIMD_WINMAP_START) >> 2;
+        old_value = s->window[w].winmap;
+        s->window[w].winmap = val;
+        if ((val & FIMD_WINMAP_EN) ^ (old_value & FIMD_WINMAP_EN)) {
+            exynos4210_fimd_invalidate(s);
+            exynos4210_fimd_update_win_bppmode(s, w);
+            exynos4210_fimd_trace_bppmode(s, w, 0xFFFFFFFF);
+            exynos4210_fimd_update(s);
+        }
+        break;
+    case FIMD_WPALCON_HIGH ... FIMD_WPALCON_LOW:
+        i = (offset - FIMD_WPALCON_HIGH) >> 2;
+        s->wpalcon[i] = val;
+        if (s->wpalcon[1] & FIMD_WPALCON_UPDATEEN) {
+            for (w = 0; w < NUM_OF_WINDOWS; w++) {
+                exynos4210_fimd_update_win_bppmode(s, w);
+                fimd_update_get_alpha(s, w);
+            }
+        }
+        break;
+    case FIMD_TRIGCON:
+        val = (val & ~FIMD_TRIGCON_ROMASK) | (s->trigcon & FIMD_TRIGCON_ROMASK);
+        s->trigcon = val;
+        break;
+    case FIMD_I80IFCON_START ... FIMD_I80IFCON_END:
+        s->i80ifcon[(offset - FIMD_I80IFCON_START) >> 2] = val;
+        break;
+    case FIMD_COLORGAINCON:
+        s->colorgaincon = val;
+        break;
+    case FIMD_LDI_CMDCON0 ... FIMD_LDI_CMDCON1:
+        s->ldi_cmdcon[(offset - FIMD_LDI_CMDCON0) >> 2] = val;
+        break;
+    case FIMD_SIFCCON0 ... FIMD_SIFCCON2:
+        i = (offset - FIMD_SIFCCON0) >> 2;
+        if (i != 2) {
+            s->sifccon[i] = val;
+        }
+        break;
+    case FIMD_HUECOEFCR_START ... FIMD_HUECOEFCR_END:
+        i = (offset - FIMD_HUECOEFCR_START) >> 2;
+        s->huecoef_cr[i] = val;
+        break;
+    case FIMD_HUECOEFCB_START ... FIMD_HUECOEFCB_END:
+        i = (offset - FIMD_HUECOEFCB_START) >> 2;
+        s->huecoef_cb[i] = val;
+        break;
+    case FIMD_HUEOFFSET:
+        s->hueoffset = val;
+        break;
+    case FIMD_VIDWALPHA_START ... FIMD_VIDWALPHA_END:
+        w = ((offset - FIMD_VIDWALPHA_START) >> 3);
+        i = ((offset - FIMD_VIDWALPHA_START) >> 2) & 1;
+        if (w == 0) {
+            s->window[w].alpha_val[i] = val;
+        } else {
+            s->window[w].alpha_val[i] = (val & FIMD_VIDALPHA_ALPHA_LOWER) |
+                (s->window[w].alpha_val[i] & FIMD_VIDALPHA_ALPHA_UPPER);
+        }
+        break;
+    case FIMD_BLENDEQ_START ... FIMD_BLENDEQ_END:
+        s->window[(offset - FIMD_BLENDEQ_START) >> 2].blendeq = val;
+        break;
+    case FIMD_BLENDCON:
+        old_value = s->blendcon;
+        s->blendcon = val;
+        if ((s->blendcon & FIMD_ALPHA_8BIT) != (old_value & FIMD_ALPHA_8BIT)) {
+            for (w = 0; w < NUM_OF_WINDOWS; w++) {
+                fimd_update_get_alpha(s, w);
+            }
+        }
+        break;
+    case FIMD_WRTQOSCON_START ... FIMD_WRTQOSCON_END:
+        s->window[(offset - FIMD_WRTQOSCON_START) >> 2].rtqoscon = val;
+        break;
+    case FIMD_I80IFCMD_START ... FIMD_I80IFCMD_END:
+        s->i80ifcmd[(offset - FIMD_I80IFCMD_START) >> 2] = val;
+        break;
+    case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2:
+        if (offset & 0x0004) {
+            DPRINT_ERROR("bad write offset 0x%08x\n", offset);
+            break;
+        }
+        w = (offset - FIMD_VIDW0ADD0_B2) >> 3;
+        if (fimd_get_buffer_id(&s->window[w]) == 2 &&
+                s->window[w].buf_start[2] != val) {
+            s->window[w].buf_start[2] = val;
+            fimd_update_memory_section(s, w);
+            break;
+        }
+        s->window[w].buf_start[2] = val;
+        break;
+    case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END:
+        if (offset & 0x0004) {
+            DPRINT_ERROR("bad write offset 0x%08x\n", offset);
+            break;
+        }
+        s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start = val;
+        break;
+    case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END:
+        if (offset & 0x0004) {
+            DPRINT_ERROR("bad write offset 0x%08x\n", offset);
+            break;
+        }
+        s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end = val;
+        break;
+    case FIMD_SHD_ADD2_START ... FIMD_SHD_ADD2_END:
+        s->window[(offset - FIMD_SHD_ADD2_START) >> 2].shadow_buf_size = val;
+        break;
+    case FIMD_PAL_MEM_START ... FIMD_PAL_MEM_END:
+        w = (offset - FIMD_PAL_MEM_START) >> 10;
+        i = ((offset - FIMD_PAL_MEM_START) >> 2) & 0xFF;
+        s->window[w].palette[i] = val;
+        break;
+    case FIMD_PALMEM_AL_START ... FIMD_PALMEM_AL_END:
+        /* Palette memory aliases for windows 0 and 1 */
+        w = (offset - FIMD_PALMEM_AL_START) >> 10;
+        i = ((offset - FIMD_PALMEM_AL_START) >> 2) & 0xFF;
+        s->window[w].palette[i] = val;
+        break;
+    default:
+        DPRINT_ERROR("bad write offset 0x%08x\n", offset);
+        break;
+    }
+}
+
+static uint64_t exynos4210_fimd_read(void *opaque, target_phys_addr_t offset,
+                                  unsigned size)
+{
+    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
+    int w, i;
+    uint32_t ret = 0;
+
+    DPRINT_L2("read offset 0x%08x\n", offset);
+
+    switch (offset) {
+    case FIMD_VIDCON0 ... FIMD_VIDCON3:
+        return s->vidcon[(offset - FIMD_VIDCON0) >> 2];
+    case FIMD_VIDTCON_START ... FIMD_VIDTCON_END:
+        return s->vidtcon[(offset - FIMD_VIDTCON_START) >> 2];
+    case FIMD_WINCON_START ... FIMD_WINCON_END:
+        return s->window[(offset - FIMD_WINCON_START) >> 2].wincon;
+    case FIMD_SHADOWCON:
+        return s->shadowcon;
+    case FIMD_WINCHMAP:
+        return s->winchmap;
+    case FIMD_VIDOSD_START ... FIMD_VIDOSD_END:
+        w = (offset - FIMD_VIDOSD_START) >> 4;
+        i = ((offset - FIMD_VIDOSD_START) & 0xF) >> 2;
+        switch (i) {
+        case 0:
+            ret = ((s->window[w].lefttop_x & FIMD_VIDOSD_COORD_MASK) <<
+            FIMD_VIDOSD_HOR_SHIFT) |
+            (s->window[w].lefttop_y & FIMD_VIDOSD_COORD_MASK);
+            break;
+        case 1:
+            ret = ((s->window[w].rightbot_x & FIMD_VIDOSD_COORD_MASK) <<
+                FIMD_VIDOSD_HOR_SHIFT) |
+                (s->window[w].rightbot_y & FIMD_VIDOSD_COORD_MASK);
+            break;
+        case 2:
+            if (w == 0) {
+                ret = s->window[w].osdsize;
+            } else {
+                ret = (pack_upper_4(s->window[w].alpha_val[0]) <<
+                    FIMD_VIDOSD_AEN0_SHIFT) |
+                    pack_upper_4(s->window[w].alpha_val[1]);
+            }
+            break;
+        case 3:
+            if (w != 1 && w != 2) {
+                DPRINT_ERROR("bad read offset 0x%08x\n", offset);
+                return 0xBAADBAAD;
+            }
+            ret = s->window[w].osdsize;
+            break;
+        }
+        return ret;
+    case FIMD_VIDWADD0_START ... FIMD_VIDWADD0_END:
+        w = (offset - FIMD_VIDWADD0_START) >> 3;
+        i = ((offset - FIMD_VIDWADD0_START) >> 2) & 1;
+        return s->window[w].buf_start[i];
+    case FIMD_VIDWADD1_START ... FIMD_VIDWADD1_END:
+        w = (offset - FIMD_VIDWADD1_START) >> 3;
+        i = ((offset - FIMD_VIDWADD1_START) >> 2) & 1;
+        return s->window[w].buf_end[i];
+    case FIMD_VIDWADD2_START ... FIMD_VIDWADD2_END:
+        w = (offset - FIMD_VIDWADD2_START) >> 2;
+        return s->window[w].virtpage_width | (s->window[w].virtpage_offsize <<
+            FIMD_VIDWADD2_OFFSIZE_SHIFT);
+    case FIMD_VIDINTCON0 ... FIMD_VIDINTCON1:
+        return s->vidintcon[(offset - FIMD_VIDINTCON0) >> 2];
+    case FIMD_WKEYCON_START ... FIMD_WKEYCON_END:
+        w = ((offset - FIMD_WKEYCON_START) >> 3) + 1;
+        i = ((offset - FIMD_WKEYCON_START) >> 2) & 1;
+        return s->window[w].keycon[i];
+    case FIMD_WKEYALPHA_START ... FIMD_WKEYALPHA_END:
+        w = ((offset - FIMD_WKEYALPHA_START) >> 2) + 1;
+        return s->window[w].keyalpha;
+    case FIMD_DITHMODE:
+        return s->dithmode;
+    case FIMD_WINMAP_START ... FIMD_WINMAP_END:
+        return s->window[(offset - FIMD_WINMAP_START) >> 2].winmap;
+    case FIMD_WPALCON_HIGH ... FIMD_WPALCON_LOW:
+        return s->wpalcon[(offset - FIMD_WPALCON_HIGH) >> 2];
+    case FIMD_TRIGCON:
+        return s->trigcon;
+    case FIMD_I80IFCON_START ... FIMD_I80IFCON_END:
+        return s->i80ifcon[(offset - FIMD_I80IFCON_START) >> 2];
+    case FIMD_COLORGAINCON:
+        return s->colorgaincon;
+    case FIMD_LDI_CMDCON0 ... FIMD_LDI_CMDCON1:
+        return s->ldi_cmdcon[(offset - FIMD_LDI_CMDCON0) >> 2];
+    case FIMD_SIFCCON0 ... FIMD_SIFCCON2:
+        i = (offset - FIMD_SIFCCON0) >> 2;
+        return s->sifccon[i];
+    case FIMD_HUECOEFCR_START ... FIMD_HUECOEFCR_END:
+        i = (offset - FIMD_HUECOEFCR_START) >> 2;
+        return s->huecoef_cr[i];
+    case FIMD_HUECOEFCB_START ... FIMD_HUECOEFCB_END:
+        i = (offset - FIMD_HUECOEFCB_START) >> 2;
+        return s->huecoef_cb[i];
+    case FIMD_HUEOFFSET:
+        return s->hueoffset;
+    case FIMD_VIDWALPHA_START ... FIMD_VIDWALPHA_END:
+        w = ((offset - FIMD_VIDWALPHA_START) >> 3);
+        i = ((offset - FIMD_VIDWALPHA_START) >> 2) & 1;
+        return s->window[w].alpha_val[i] &
+                (w == 0 ? 0xFFFFFF : FIMD_VIDALPHA_ALPHA_LOWER);
+    case FIMD_BLENDEQ_START ... FIMD_BLENDEQ_END:
+        return s->window[(offset - FIMD_BLENDEQ_START) >> 2].blendeq;
+    case FIMD_BLENDCON:
+        return s->blendcon;
+    case FIMD_WRTQOSCON_START ... FIMD_WRTQOSCON_END:
+        return s->window[(offset - FIMD_WRTQOSCON_START) >> 2].rtqoscon;
+    case FIMD_I80IFCMD_START ... FIMD_I80IFCMD_END:
+        return s->i80ifcmd[(offset - FIMD_I80IFCMD_START) >> 2];
+    case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2:
+        if (offset & 0x0004) {
+            break;
+        }
+        return s->window[(offset - FIMD_VIDW0ADD0_B2) >> 3].buf_start[2];
+    case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END:
+        if (offset & 0x0004) {
+            break;
+        }
+        return s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start;
+    case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END:
+        if (offset & 0x0004) {
+            break;
+        }
+        return s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end;
+    case FIMD_SHD_ADD2_START ... FIMD_SHD_ADD2_END:
+        return s->window[(offset - FIMD_SHD_ADD2_START) >> 2].shadow_buf_size;
+    case FIMD_PAL_MEM_START ... FIMD_PAL_MEM_END:
+        w = (offset - FIMD_PAL_MEM_START) >> 10;
+        i = ((offset - FIMD_PAL_MEM_START) >> 2) & 0xFF;
+        return s->window[w].palette[i];
+    case FIMD_PALMEM_AL_START ... FIMD_PALMEM_AL_END:
+        /* Palette aliases for win 0,1 */
+        w = (offset - FIMD_PALMEM_AL_START) >> 10;
+        i = ((offset - FIMD_PALMEM_AL_START) >> 2) & 0xFF;
+        return s->window[w].palette[i];
+    }
+
+    DPRINT_ERROR("bad read offset 0x%08x\n", offset);
+    return 0xBAADBAAD;
+}
+
+static const MemoryRegionOps exynos4210_fimd_mmio_ops = {
+    .read = exynos4210_fimd_read,
+    .write = exynos4210_fimd_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int exynos4210_fimd_load(void *opaque, int version_id)
+{
+    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
+    int w;
+
+    if (version_id != 1) {
+        return -EINVAL;
+    }
+
+    for (w = 0; w < NUM_OF_WINDOWS; w++) {
+        exynos4210_fimd_update_win_bppmode(s, w);
+        fimd_update_get_alpha(s, w);
+        fimd_update_memory_section(s, w);
+    }
+
+    /* Redraw the whole screen */
+    exynos4210_update_resolution(s);
+    exynos4210_fimd_invalidate(s);
+    exynos4210_fimd_enable(s, (s->vidcon[0] & FIMD_VIDCON0_ENVID_MASK) ==
+            FIMD_VIDCON0_ENVID_MASK);
+    return 0;
+}
+
+static const VMStateDescription exynos4210_fimd_window_vmstate = {
+    .name = "exynos4210.fimd_window",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(wincon, Exynos4210fimdWindow),
+        VMSTATE_UINT32_ARRAY(buf_start, Exynos4210fimdWindow, 3),
+        VMSTATE_UINT32_ARRAY(buf_end, Exynos4210fimdWindow, 3),
+        VMSTATE_UINT32_ARRAY(keycon, Exynos4210fimdWindow, 2),
+        VMSTATE_UINT32(keyalpha, Exynos4210fimdWindow),
+        VMSTATE_UINT32(winmap, Exynos4210fimdWindow),
+        VMSTATE_UINT32(blendeq, Exynos4210fimdWindow),
+        VMSTATE_UINT32(rtqoscon, Exynos4210fimdWindow),
+        VMSTATE_UINT32_ARRAY(palette, Exynos4210fimdWindow, 256),
+        VMSTATE_UINT32(shadow_buf_start, Exynos4210fimdWindow),
+        VMSTATE_UINT32(shadow_buf_end, Exynos4210fimdWindow),
+        VMSTATE_UINT32(shadow_buf_size, Exynos4210fimdWindow),
+        VMSTATE_UINT16(lefttop_x, Exynos4210fimdWindow),
+        VMSTATE_UINT16(lefttop_y, Exynos4210fimdWindow),
+        VMSTATE_UINT16(rightbot_x, Exynos4210fimdWindow),
+        VMSTATE_UINT16(rightbot_y, Exynos4210fimdWindow),
+        VMSTATE_UINT32(osdsize, Exynos4210fimdWindow),
+        VMSTATE_UINT32_ARRAY(alpha_val, Exynos4210fimdWindow, 2),
+        VMSTATE_UINT16(virtpage_width, Exynos4210fimdWindow),
+        VMSTATE_UINT16(virtpage_offsize, Exynos4210fimdWindow),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription exynos4210_fimd_vmstate = {
+    .name = "exynos4210.fimd",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = exynos4210_fimd_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(vidcon, Exynos4210fimdState, 4),
+        VMSTATE_UINT32_ARRAY(vidtcon, Exynos4210fimdState, 4),
+        VMSTATE_UINT32(shadowcon, Exynos4210fimdState),
+        VMSTATE_UINT32(winchmap, Exynos4210fimdState),
+        VMSTATE_UINT32_ARRAY(vidintcon, Exynos4210fimdState, 2),
+        VMSTATE_UINT32(dithmode, Exynos4210fimdState),
+        VMSTATE_UINT32_ARRAY(wpalcon, Exynos4210fimdState, 2),
+        VMSTATE_UINT32(trigcon, Exynos4210fimdState),
+        VMSTATE_UINT32_ARRAY(i80ifcon, Exynos4210fimdState, 4),
+        VMSTATE_UINT32(colorgaincon, Exynos4210fimdState),
+        VMSTATE_UINT32_ARRAY(ldi_cmdcon, Exynos4210fimdState, 2),
+        VMSTATE_UINT32_ARRAY(sifccon, Exynos4210fimdState, 3),
+        VMSTATE_UINT32_ARRAY(huecoef_cr, Exynos4210fimdState, 4),
+        VMSTATE_UINT32_ARRAY(huecoef_cb, Exynos4210fimdState, 4),
+        VMSTATE_UINT32(hueoffset, Exynos4210fimdState),
+        VMSTATE_UINT32_ARRAY(i80ifcmd, Exynos4210fimdState, 12),
+        VMSTATE_UINT32(blendcon, Exynos4210fimdState),
+        VMSTATE_STRUCT_ARRAY(window, Exynos4210fimdState, 5, 1,
+                exynos4210_fimd_window_vmstate, Exynos4210fimdWindow),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int exynos4210_fimd_init(SysBusDevice *dev)
+{
+    Exynos4210fimdState *s = FROM_SYSBUS(Exynos4210fimdState, dev);
+
+    s->ifb = NULL;
+
+    sysbus_init_irq(dev, &s->irq[0]);
+    sysbus_init_irq(dev, &s->irq[1]);
+    sysbus_init_irq(dev, &s->irq[2]);
+
+    memory_region_init_io(&s->iomem, &exynos4210_fimd_mmio_ops, s,
+            "exynos4210.fimd", FIMD_REGS_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+    s->console = graphic_console_init(exynos4210_fimd_update,
+                                  exynos4210_fimd_invalidate, NULL, NULL, s);
+
+    return 0;
+}
+
+static void exynos4210_fimd_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    dc->vmsd = &exynos4210_fimd_vmstate;
+    dc->reset = exynos4210_fimd_reset;
+    k->init = exynos4210_fimd_init;
+}
+
+static TypeInfo exynos4210_fimd_info = {
+    .name = "exynos4210.fimd",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210fimdState),
+    .class_init = exynos4210_fimd_class_init,
+};
+
+static void exynos4210_fimd_register_types(void)
+{
+    type_register_static(&exynos4210_fimd_info);
+}
+
+type_init(exynos4210_fimd_register_types)
commit 2c2c6496f83b1746a118dbcb2a0e4f8c0305c2a8
Author: Evgeny Voevodin <e.voevodin at samsung.com>
Date:   Thu Feb 16 09:56:06 2012 +0000

    hw/exynos4210.c: Add LAN support for SMDKC210.
    
    SMDKC210 uses lan9215 chip, but lan9118 in 16-bit mode seems to
    be enough.
    
    Signed-off-by: Evgeny Voevodin <e.voevodin at samsung.com>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/exynos4_boards.c b/hw/exynos4_boards.c
index 767dc45..329efbe 100644
--- a/hw/exynos4_boards.c
+++ b/hw/exynos4_boards.c
@@ -23,6 +23,7 @@
 
 #include "sysemu.h"
 #include "sysbus.h"
+#include "net.h"
 #include "arm-misc.h"
 #include "exec-memory.h"
 #include "exynos4210.h"
@@ -42,6 +43,8 @@
     #define  PRINT_DEBUG(fmt, args...)  do {} while (0)
 #endif
 
+#define SMDK_LAN9118_BASE_ADDR      0x05000000
+
 typedef enum Exynos4BoardType {
     EXYNOS4_BOARD_NURI,
     EXYNOS4_BOARD_SMDKC210,
@@ -71,6 +74,24 @@ static struct arm_boot_info exynos4_board_binfo = {
 
 static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS];
 
+static void lan9215_init(uint32_t base, qemu_irq irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    /* This should be a 9215 but the 9118 is close enough */
+    if (nd_table[0].vlan) {
+        qemu_check_nic_model(&nd_table[0], "lan9118");
+        dev = qdev_create(NULL, "lan9118");
+        qdev_set_nic_properties(dev, &nd_table[0]);
+        qdev_prop_set_uint32(dev, "mode_16bit", 1);
+        qdev_init_nofail(dev);
+        s = sysbus_from_qdev(dev);
+        sysbus_mmio_map(s, 0, base);
+        sysbus_connect_irq(s, 0, irq);
+    }
+}
+
 static Exynos4210State *exynos4_boards_init_common(
         const char *kernel_filename,
         const char *kernel_cmdline,
@@ -123,9 +144,11 @@ static void smdkc210_init(ram_addr_t ram_size,
         const char *kernel_filename, const char *kernel_cmdline,
         const char *initrd_filename, const char *cpu_model)
 {
-    exynos4_boards_init_common(kernel_filename, kernel_cmdline,
-                initrd_filename, EXYNOS4_BOARD_SMDKC210);
+    Exynos4210State *s = exynos4_boards_init_common(kernel_filename,
+            kernel_cmdline, initrd_filename, EXYNOS4_BOARD_SMDKC210);
 
+    lan9215_init(SMDK_LAN9118_BASE_ADDR,
+            qemu_irq_invert(s->irq_table[exynos4210_get_irq(37, 1)]));
     arm_load_kernel(first_cpu, &exynos4_board_binfo);
 }
 
commit 1248f8d4cbc3cd7b7956510f9d72188b5cd37287
Author: Evgeny Voevodin <e.voevodin at samsung.com>
Date:   Thu Feb 16 09:56:06 2012 +0000

    hw/lan9118: Add basic 16-bit mode support.
    
    Signed-off-by: Evgeny Voevodin <e.voevodin at samsung.com>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/lan9118.c b/hw/lan9118.c
index aeb0c39..7b4fe87 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -235,11 +235,21 @@ typedef struct {
     int32_t rxp_offset;
     int32_t rxp_size;
     int32_t rxp_pad;
+
+    uint32_t write_word_prev_offset;
+    uint32_t write_word_n;
+    uint16_t write_word_l;
+    uint16_t write_word_h;
+    uint32_t read_word_prev_offset;
+    uint32_t read_word_n;
+    uint32_t read_long;
+
+    uint32_t mode_16bit;
 } lan9118_state;
 
 static const VMStateDescription vmstate_lan9118 = {
     .name = "lan9118",
-    .version_id = 1,
+    .version_id = 2,
     .minimum_version_id = 1,
     .fields = (VMStateField[]) {
         VMSTATE_PTIMER(timer, lan9118_state),
@@ -294,6 +304,14 @@ static const VMStateDescription vmstate_lan9118 = {
         VMSTATE_INT32(rxp_offset, lan9118_state),
         VMSTATE_INT32(rxp_size, lan9118_state),
         VMSTATE_INT32(rxp_pad, lan9118_state),
+        VMSTATE_UINT32_V(write_word_prev_offset, lan9118_state, 2),
+        VMSTATE_UINT32_V(write_word_n, lan9118_state, 2),
+        VMSTATE_UINT16_V(write_word_l, lan9118_state, 2),
+        VMSTATE_UINT16_V(write_word_h, lan9118_state, 2),
+        VMSTATE_UINT32_V(read_word_prev_offset, lan9118_state, 2),
+        VMSTATE_UINT32_V(read_word_n, lan9118_state, 2),
+        VMSTATE_UINT32_V(read_long, lan9118_state, 2),
+        VMSTATE_UINT32_V(mode_16bit, lan9118_state, 2),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -390,7 +408,7 @@ static void lan9118_reset(DeviceState *d)
     s->fifo_int = 0x48000000;
     s->rx_cfg = 0;
     s->tx_cfg = 0;
-    s->hw_cfg = 0x00050000;
+    s->hw_cfg = s->mode_16bit ? 0x00050000 : 0x00050004;
     s->pmt_ctrl &= 0x45;
     s->gpio_cfg = 0;
     s->txp->fifo_used = 0;
@@ -429,6 +447,9 @@ static void lan9118_reset(DeviceState *d)
     s->mac_mii_data = 0;
     s->mac_flow = 0;
 
+    s->read_word_n = 0;
+    s->write_word_n = 0;
+
     phy_reset(s);
 
     s->eeprom_writable = 0;
@@ -984,7 +1005,7 @@ static void lan9118_writel(void *opaque, target_phys_addr_t offset,
 {
     lan9118_state *s = (lan9118_state *)opaque;
     offset &= 0xff;
-    
+
     //DPRINTF("Write reg 0x%02x = 0x%08x\n", (int)offset, val);
     if (offset >= 0x20 && offset < 0x40) {
         /* TX FIFO */
@@ -1034,7 +1055,7 @@ static void lan9118_writel(void *opaque, target_phys_addr_t offset,
             /* SRST */
             lan9118_reset(&s->busdev.qdev);
         } else {
-            s->hw_cfg = val & 0x003f300;
+            s->hw_cfg = (val & 0x003f300) | (s->hw_cfg & 0x4);
         }
         break;
     case CSR_RX_DP_CTRL:
@@ -1113,6 +1134,46 @@ static void lan9118_writel(void *opaque, target_phys_addr_t offset,
     lan9118_update(s);
 }
 
+static void lan9118_writew(void *opaque, target_phys_addr_t offset,
+                           uint32_t val)
+{
+    lan9118_state *s = (lan9118_state *)opaque;
+    offset &= 0xff;
+
+    if (s->write_word_prev_offset != (offset & ~0x3)) {
+        /* New offset, reset word counter */
+        s->write_word_n = 0;
+        s->write_word_prev_offset = offset & ~0x3;
+    }
+
+    if (offset & 0x2) {
+        s->write_word_h = val;
+    } else {
+        s->write_word_l = val;
+    }
+
+    //DPRINTF("Writew reg 0x%02x = 0x%08x\n", (int)offset, val);
+    s->write_word_n++;
+    if (s->write_word_n == 2) {
+        s->write_word_n = 0;
+        lan9118_writel(s, offset & ~3, s->write_word_l +
+                (s->write_word_h << 16), 4);
+    }
+}
+
+static void lan9118_16bit_mode_write(void *opaque, target_phys_addr_t offset,
+                                     uint64_t val, unsigned size)
+{
+    switch (size) {
+    case 2:
+        return lan9118_writew(opaque, offset, (uint32_t)val);
+    case 4:
+        return lan9118_writel(opaque, offset, val, size);
+    }
+
+    hw_error("lan9118_write: Bad size 0x%x\n", size);
+}
+
 static uint64_t lan9118_readl(void *opaque, target_phys_addr_t offset,
                               unsigned size)
 {
@@ -1149,7 +1210,7 @@ static uint64_t lan9118_readl(void *opaque, target_phys_addr_t offset,
     case CSR_TX_CFG:
         return s->tx_cfg;
     case CSR_HW_CFG:
-        return s->hw_cfg | 0x4;
+        return s->hw_cfg;
     case CSR_RX_DP_CTRL:
         return 0;
     case CSR_RX_FIFO_INF:
@@ -1187,12 +1248,60 @@ static uint64_t lan9118_readl(void *opaque, target_phys_addr_t offset,
     return 0;
 }
 
+static uint32_t lan9118_readw(void *opaque, target_phys_addr_t offset)
+{
+    lan9118_state *s = (lan9118_state *)opaque;
+    uint32_t val;
+
+    if (s->read_word_prev_offset != (offset & ~0x3)) {
+        /* New offset, reset word counter */
+        s->read_word_n = 0;
+        s->read_word_prev_offset = offset & ~0x3;
+    }
+
+    s->read_word_n++;
+    if (s->read_word_n == 1) {
+        s->read_long = lan9118_readl(s, offset & ~3, 4);
+    } else {
+        s->read_word_n = 0;
+    }
+
+    if (offset & 2) {
+        val = s->read_long >> 16;
+    } else {
+        val = s->read_long & 0xFFFF;
+    }
+
+    //DPRINTF("Readw reg 0x%02x, val 0x%x\n", (int)offset, val);
+    return val;
+}
+
+static uint64_t lan9118_16bit_mode_read(void *opaque, target_phys_addr_t offset,
+                                        unsigned size)
+{
+    switch (size) {
+    case 2:
+        return lan9118_readw(opaque, offset);
+    case 4:
+        return lan9118_readl(opaque, offset, size);
+    }
+
+    hw_error("lan9118_read: Bad size 0x%x\n", size);
+    return 0;
+}
+
 static const MemoryRegionOps lan9118_mem_ops = {
     .read = lan9118_readl,
     .write = lan9118_writel,
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
+static const MemoryRegionOps lan9118_16bit_mem_ops = {
+    .read = lan9118_16bit_mode_read,
+    .write = lan9118_16bit_mode_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
 static void lan9118_cleanup(VLANClientState *nc)
 {
     lan9118_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
@@ -1214,8 +1323,10 @@ static int lan9118_init1(SysBusDevice *dev)
     lan9118_state *s = FROM_SYSBUS(lan9118_state, dev);
     QEMUBH *bh;
     int i;
+    const MemoryRegionOps *mem_ops =
+            s->mode_16bit ? &lan9118_16bit_mem_ops : &lan9118_mem_ops;
 
-    memory_region_init_io(&s->mmio, &lan9118_mem_ops, s, "lan9118-mmio", 0x100);
+    memory_region_init_io(&s->mmio, mem_ops, s, "lan9118-mmio", 0x100);
     sysbus_init_mmio(dev, &s->mmio);
     sysbus_init_irq(dev, &s->irq);
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
@@ -1240,6 +1351,7 @@ static int lan9118_init1(SysBusDevice *dev)
 
 static Property lan9118_properties[] = {
     DEFINE_NIC_PROPERTIES(lan9118_state, conf),
+    DEFINE_PROP_UINT32("mode_16bit", lan9118_state, mode_16bit, 0),
     DEFINE_PROP_END_OF_LIST(),
 };
 
commit 12c775db14c037715e31079e2c17899abd0a2aa6
Author: Evgeny Voevodin <e.voevodin at samsung.com>
Date:   Thu Feb 16 09:56:05 2012 +0000

    ARM: exynos4210: MCT support.
    
    Signed-off-by: Evgeny Voevodin <e.voevodin at samsung.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/Makefile.target b/Makefile.target
index 8a7b4d2..6ceff54 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -346,7 +346,7 @@ obj-arm-y += versatile_pci.o
 obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
 obj-arm-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
 obj-arm-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
-obj-arm-y += exynos4210_pmu.o
+obj-arm-y += exynos4210_pmu.o exynos4210_mct.o
 obj-arm-y += arm_l2x0.o
 obj-arm-y += arm_mptimer.o
 obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
diff --git a/hw/exynos4210.c b/hw/exynos4210.c
index f922f55..558f669 100644
--- a/hw/exynos4210.c
+++ b/hw/exynos4210.c
@@ -32,6 +32,9 @@
 /* PWM */
 #define EXYNOS4210_PWM_BASE_ADDR       0x139D0000
 
+/* MCT */
+#define EXYNOS4210_MCT_BASE_ADDR       0x10050000
+
 /* UART's definitions */
 #define EXYNOS4210_UART0_BASE_ADDR     0x13800000
 #define EXYNOS4210_UART1_BASE_ADDR     0x13810000
@@ -220,6 +223,22 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
                           s->irq_table[exynos4210_get_irq(22, 4)],
                           NULL);
 
+    /* Multi Core Timer */
+    dev = qdev_create(NULL, "exynos4210.mct");
+    qdev_init_nofail(dev);
+    busdev = sysbus_from_qdev(dev);
+    for (n = 0; n < 4; n++) {
+        /* Connect global timer interrupts to Combiner gpio_in */
+        sysbus_connect_irq(busdev, n,
+                s->irq_table[exynos4210_get_irq(1, 4 + n)]);
+    }
+    /* Connect local timer interrupts to Combiner gpio_in */
+    sysbus_connect_irq(busdev, 4,
+            s->irq_table[exynos4210_get_irq(51, 0)]);
+    sysbus_connect_irq(busdev, 5,
+            s->irq_table[exynos4210_get_irq(35, 3)]);
+    sysbus_mmio_map(busdev, 0, EXYNOS4210_MCT_BASE_ADDR);
+
     /*** UARTs ***/
     exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR,
                            EXYNOS4210_UART0_FIFO_SIZE, 0, NULL,
diff --git a/hw/exynos4210_mct.c b/hw/exynos4210_mct.c
new file mode 100644
index 0000000..01e3fb8
--- /dev/null
+++ b/hw/exynos4210_mct.c
@@ -0,0 +1,1488 @@
+/*
+ * Samsung exynos4210 Multi Core timer
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ * All rights reserved.
+ *
+ * Evgeny Voevodin <e.voevodin at samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program 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 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/>.
+ */
+
+/*
+ * Global Timer:
+ *
+ * Consists of two timers. First represents Free Running Counter and second
+ * is used to measure interval from FRC to nearest comparator.
+ *
+ *        0                                                           UINT64_MAX
+ *        |                              timer0                             |
+ *        | <-------------------------------------------------------------- |
+ *        | --------------------------------------------frc---------------> |
+ *        |______________________________________________|__________________|
+ *                CMP0          CMP1             CMP2    |           CMP3
+ *                                                     __|            |_
+ *                                                     |     timer1     |
+ *                                                     | -------------> |
+ *                                                    frc              CMPx
+ *
+ * Problem: when implementing global timer as is, overflow arises.
+ * next_time = cur_time + period * count;
+ * period and count are 64 bits width.
+ * Lets arm timer for MCT_GT_COUNTER_STEP count and update internal G_CNT
+ * register during each event.
+ *
+ * Problem: both timers need to be implemented using MCT_XT_COUNTER_STEP because
+ * local timer contains two counters: TCNT and ICNT. TCNT == 0 -> ICNT--.
+ * IRQ is generated when ICNT riches zero. Implementation where TCNT == 0
+ * generates IRQs suffers from too frequently events. Better to have one
+ * uint64_t counter equal to TCNT*ICNT and arm ptimer.c for a minimum(TCNT*ICNT,
+ * MCT_GT_COUNTER_STEP); (yes, if target tunes ICNT * TCNT to be too low values,
+ * there is no way to avoid frequently events).
+ */
+
+#include "sysbus.h"
+#include "qemu-timer.h"
+#include "qemu-common.h"
+#include "ptimer.h"
+
+#include "exynos4210.h"
+
+//#define DEBUG_MCT
+
+#ifdef DEBUG_MCT
+#define DPRINTF(fmt, ...) \
+        do { fprintf(stdout, "MCT: [%24s:%5d] " fmt, __func__, __LINE__, \
+                     ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define    MCT_CFG          0x000
+#define    G_CNT_L          0x100
+#define    G_CNT_U          0x104
+#define    G_CNT_WSTAT      0x110
+#define    G_COMP0_L        0x200
+#define    G_COMP0_U        0x204
+#define    G_COMP0_ADD_INCR 0x208
+#define    G_COMP1_L        0x210
+#define    G_COMP1_U        0x214
+#define    G_COMP1_ADD_INCR 0x218
+#define    G_COMP2_L        0x220
+#define    G_COMP2_U        0x224
+#define    G_COMP2_ADD_INCR 0x228
+#define    G_COMP3_L        0x230
+#define    G_COMP3_U        0x234
+#define    G_COMP3_ADD_INCR 0x238
+#define    G_TCON           0x240
+#define    G_INT_CSTAT      0x244
+#define    G_INT_ENB        0x248
+#define    G_WSTAT          0x24C
+#define    L0_TCNTB         0x300
+#define    L0_TCNTO         0x304
+#define    L0_ICNTB         0x308
+#define    L0_ICNTO         0x30C
+#define    L0_FRCNTB        0x310
+#define    L0_FRCNTO        0x314
+#define    L0_TCON          0x320
+#define    L0_INT_CSTAT     0x330
+#define    L0_INT_ENB       0x334
+#define    L0_WSTAT         0x340
+#define    L1_TCNTB         0x400
+#define    L1_TCNTO         0x404
+#define    L1_ICNTB         0x408
+#define    L1_ICNTO         0x40C
+#define    L1_FRCNTB        0x410
+#define    L1_FRCNTO        0x414
+#define    L1_TCON          0x420
+#define    L1_INT_CSTAT     0x430
+#define    L1_INT_ENB       0x434
+#define    L1_WSTAT         0x440
+
+#define MCT_CFG_GET_PRESCALER(x)    ((x) & 0xFF)
+#define MCT_CFG_GET_DIVIDER(x)      (1 << ((x) >> 8 & 7))
+
+#define GET_G_COMP_IDX(offset)          (((offset) - G_COMP0_L) / 0x10)
+#define GET_G_COMP_ADD_INCR_IDX(offset) (((offset) - G_COMP0_ADD_INCR) / 0x10)
+
+#define G_COMP_L(x) (G_COMP0_L + (x) * 0x10)
+#define G_COMP_U(x) (G_COMP0_U + (x) * 0x10)
+
+#define G_COMP_ADD_INCR(x)  (G_COMP0_ADD_INCR + (x) * 0x10)
+
+/* MCT bits */
+#define G_TCON_COMP_ENABLE(x)   (1 << 2 * (x))
+#define G_TCON_AUTO_ICREMENT(x) (1 << (2 * (x) + 1))
+#define G_TCON_TIMER_ENABLE     (1 << 8)
+
+#define G_INT_ENABLE(x)         (1 << (x))
+#define G_INT_CSTAT_COMP(x)     (1 << (x))
+
+#define G_CNT_WSTAT_L           1
+#define G_CNT_WSTAT_U           2
+
+#define G_WSTAT_COMP_L(x)       (1 << 4 * (x))
+#define G_WSTAT_COMP_U(x)       (1 << ((4 * (x)) + 1))
+#define G_WSTAT_COMP_ADDINCR(x) (1 << ((4 * (x)) + 2))
+#define G_WSTAT_TCON_WRITE      (1 << 16)
+
+#define GET_L_TIMER_IDX(offset) ((((offset) & 0xF00) - L0_TCNTB) / 0x100)
+#define GET_L_TIMER_CNT_REG_IDX(offset, lt_i) \
+        (((offset) - (L0_TCNTB + 0x100 * (lt_i))) >> 2)
+
+#define L_ICNTB_MANUAL_UPDATE   (1 << 31)
+
+#define L_TCON_TICK_START       (1)
+#define L_TCON_INT_START        (1 << 1)
+#define L_TCON_INTERVAL_MODE    (1 << 2)
+#define L_TCON_FRC_START        (1 << 3)
+
+#define L_INT_CSTAT_INTCNT      (1 << 0)
+#define L_INT_CSTAT_FRCCNT      (1 << 1)
+
+#define L_INT_INTENB_ICNTEIE    (1 << 0)
+#define L_INT_INTENB_FRCEIE     (1 << 1)
+
+#define L_WSTAT_TCNTB_WRITE     (1 << 0)
+#define L_WSTAT_ICNTB_WRITE     (1 << 1)
+#define L_WSTAT_FRCCNTB_WRITE   (1 << 2)
+#define L_WSTAT_TCON_WRITE      (1 << 3)
+
+enum LocalTimerRegCntIndexes {
+    L_REG_CNT_TCNTB,
+    L_REG_CNT_TCNTO,
+    L_REG_CNT_ICNTB,
+    L_REG_CNT_ICNTO,
+    L_REG_CNT_FRCCNTB,
+    L_REG_CNT_FRCCNTO,
+
+    L_REG_CNT_AMOUNT
+};
+
+#define MCT_NIRQ                6
+#define MCT_SFR_SIZE            0x444
+
+#define MCT_GT_CMP_NUM          4
+
+#define MCT_GT_MAX_VAL          UINT64_MAX
+
+#define MCT_GT_COUNTER_STEP     0x100000000ULL
+#define MCT_LT_COUNTER_STEP     0x100000000ULL
+#define MCT_LT_CNT_LOW_LIMIT    0x100
+
+/* global timer */
+typedef struct {
+    qemu_irq  irq[MCT_GT_CMP_NUM];
+
+    struct gregs {
+        uint64_t cnt;
+        uint32_t cnt_wstat;
+        uint32_t tcon;
+        uint32_t int_cstat;
+        uint32_t int_enb;
+        uint32_t wstat;
+        uint64_t comp[MCT_GT_CMP_NUM];
+        uint32_t comp_add_incr[MCT_GT_CMP_NUM];
+    } reg;
+
+    uint64_t count;            /* Value FRC was armed with */
+    int32_t curr_comp;             /* Current comparator FRC is running to */
+
+    ptimer_state *ptimer_frc;                   /* FRC timer */
+
+} Exynos4210MCTGT;
+
+/* local timer */
+typedef struct {
+    int         id;             /* timer id */
+    qemu_irq    irq;            /* local timer irq */
+
+    struct tick_timer {
+        uint32_t cnt_run;           /* cnt timer is running */
+        uint32_t int_run;           /* int timer is running */
+
+        uint32_t last_icnto;
+        uint32_t last_tcnto;
+        uint32_t tcntb;             /* initial value for TCNTB */
+        uint32_t icntb;             /* initial value for ICNTB */
+
+        /* for step mode */
+        uint64_t    distance;       /* distance to count to the next event */
+        uint64_t    progress;       /* progress when counting by steps */
+        uint64_t    count;          /* count to arm timer with */
+
+        ptimer_state *ptimer_tick;  /* timer for tick counter */
+    } tick_timer;
+
+    /* use ptimer.c to represent count down timer */
+
+    ptimer_state *ptimer_frc;   /* timer for free running counter */
+
+    /* registers */
+    struct lregs {
+        uint32_t    cnt[L_REG_CNT_AMOUNT];
+        uint32_t    tcon;
+        uint32_t    int_cstat;
+        uint32_t    int_enb;
+        uint32_t    wstat;
+    } reg;
+
+} Exynos4210MCTLT;
+
+typedef struct Exynos4210MCTState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    /* Registers */
+    uint32_t    reg_mct_cfg;
+
+    Exynos4210MCTLT l_timer[2];
+    Exynos4210MCTGT g_timer;
+
+    uint32_t    freq;                   /* all timers tick frequency, TCLK */
+} Exynos4210MCTState;
+
+/*** VMState ***/
+static const VMStateDescription vmstate_tick_timer = {
+    .name = "exynos4210.mct.tick_timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(cnt_run, struct tick_timer),
+        VMSTATE_UINT32(int_run, struct tick_timer),
+        VMSTATE_UINT32(last_icnto, struct tick_timer),
+        VMSTATE_UINT32(last_tcnto, struct tick_timer),
+        VMSTATE_UINT32(tcntb, struct tick_timer),
+        VMSTATE_UINT32(icntb, struct tick_timer),
+        VMSTATE_UINT64(distance, struct tick_timer),
+        VMSTATE_UINT64(progress, struct tick_timer),
+        VMSTATE_UINT64(count, struct tick_timer),
+        VMSTATE_PTIMER(ptimer_tick, struct tick_timer),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_lregs = {
+    .name = "exynos4210.mct.lregs",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(cnt, struct lregs, L_REG_CNT_AMOUNT),
+        VMSTATE_UINT32(tcon, struct lregs),
+        VMSTATE_UINT32(int_cstat, struct lregs),
+        VMSTATE_UINT32(int_enb, struct lregs),
+        VMSTATE_UINT32(wstat, struct lregs),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_exynos4210_mct_lt = {
+    .name = "exynos4210.mct.lt",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(id, Exynos4210MCTLT),
+        VMSTATE_STRUCT(tick_timer, Exynos4210MCTLT, 0,
+                vmstate_tick_timer,
+                struct tick_timer),
+        VMSTATE_PTIMER(ptimer_frc, Exynos4210MCTLT),
+        VMSTATE_STRUCT(reg, Exynos4210MCTLT, 0,
+                vmstate_lregs,
+                struct lregs),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_gregs = {
+    .name = "exynos4210.mct.lregs",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(cnt, struct gregs),
+        VMSTATE_UINT32(cnt_wstat, struct gregs),
+        VMSTATE_UINT32(tcon, struct gregs),
+        VMSTATE_UINT32(int_cstat, struct gregs),
+        VMSTATE_UINT32(int_enb, struct gregs),
+        VMSTATE_UINT32(wstat, struct gregs),
+        VMSTATE_UINT64_ARRAY(comp, struct gregs, MCT_GT_CMP_NUM),
+        VMSTATE_UINT32_ARRAY(comp_add_incr, struct gregs,
+                MCT_GT_CMP_NUM),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_exynos4210_mct_gt = {
+    .name = "exynos4210.mct.lt",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(reg, Exynos4210MCTGT, 0, vmstate_gregs,
+                struct gregs),
+        VMSTATE_UINT64(count, Exynos4210MCTGT),
+        VMSTATE_INT32(curr_comp, Exynos4210MCTGT),
+        VMSTATE_PTIMER(ptimer_frc, Exynos4210MCTGT),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_exynos4210_mct_state = {
+    .name = "exynos4210.mct",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(reg_mct_cfg, Exynos4210MCTState),
+        VMSTATE_STRUCT_ARRAY(l_timer, Exynos4210MCTState, 2, 0,
+            vmstate_exynos4210_mct_lt, Exynos4210MCTLT),
+        VMSTATE_STRUCT(g_timer, Exynos4210MCTState, 0,
+            vmstate_exynos4210_mct_gt, Exynos4210MCTGT),
+        VMSTATE_UINT32(freq, Exynos4210MCTState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void exynos4210_mct_update_freq(Exynos4210MCTState *s);
+
+/*
+ * Set counter of FRC global timer.
+ */
+static void exynos4210_gfrc_set_count(Exynos4210MCTGT *s, uint64_t count)
+{
+    s->count = count;
+    DPRINTF("global timer frc set count 0x%llx\n", count);
+    ptimer_set_count(s->ptimer_frc, count);
+}
+
+/*
+ * Get counter of FRC global timer.
+ */
+static uint64_t exynos4210_gfrc_get_count(Exynos4210MCTGT *s)
+{
+    uint64_t count = 0;
+    count = ptimer_get_count(s->ptimer_frc);
+    if (!count) {
+        /* Timer event was generated and s->reg.cnt holds adequate value */
+        return s->reg.cnt;
+    }
+    count = s->count - count;
+    return s->reg.cnt + count;
+}
+
+/*
+ * Stop global FRC timer
+ */
+static void exynos4210_gfrc_stop(Exynos4210MCTGT *s)
+{
+    DPRINTF("global timer frc stop\n");
+
+    ptimer_stop(s->ptimer_frc);
+}
+
+/*
+ * Start global FRC timer
+ */
+static void exynos4210_gfrc_start(Exynos4210MCTGT *s)
+{
+    DPRINTF("global timer frc start\n");
+
+    ptimer_run(s->ptimer_frc, 1);
+}
+
+/*
+ * Find next nearest Comparator. If current Comparator value equals to other
+ * Comparator value, skip them both
+ */
+static int32_t exynos4210_gcomp_find(Exynos4210MCTState *s)
+{
+    int res;
+    int i;
+    int enabled;
+    uint64_t min;
+    int min_comp_i;
+    uint64_t gfrc;
+    uint64_t distance;
+    uint64_t distance_min;
+    int comp_i;
+
+    /* get gfrc count */
+    gfrc = exynos4210_gfrc_get_count(&s->g_timer);
+
+    min = UINT64_MAX;
+    distance_min = UINT64_MAX;
+    comp_i = MCT_GT_CMP_NUM;
+    min_comp_i = MCT_GT_CMP_NUM;
+    enabled = 0;
+
+    /* lookup for nearest comparator */
+    for (i = 0; i < MCT_GT_CMP_NUM; i++) {
+
+        if (s->g_timer.reg.tcon & G_TCON_COMP_ENABLE(i)) {
+
+            enabled = 1;
+
+            if (s->g_timer.reg.comp[i] > gfrc) {
+                /* Comparator is upper then FRC */
+                distance = s->g_timer.reg.comp[i] - gfrc;
+
+                if (distance <= distance_min) {
+                    distance_min = distance;
+                    comp_i = i;
+                }
+            } else {
+                /* Comparator is below FRC, find the smallest */
+
+                if (s->g_timer.reg.comp[i] <= min) {
+                    min = s->g_timer.reg.comp[i];
+                    min_comp_i = i;
+                }
+            }
+        }
+    }
+
+    if (!enabled) {
+        /* All Comparators disabled */
+        res = -1;
+    } else if (comp_i < MCT_GT_CMP_NUM) {
+        /* Found upper Comparator */
+        res = comp_i;
+    } else {
+        /* All Comparators are below or equal to FRC  */
+        res = min_comp_i;
+    }
+
+    DPRINTF("found comparator %d: comp 0x%llx distance 0x%llx, gfrc 0x%llx\n",
+            res,
+            s->g_timer.reg.comp[res],
+            distance_min,
+            gfrc);
+
+    return res;
+}
+
+/*
+ * Get distance to nearest Comparator
+ */
+static uint64_t exynos4210_gcomp_get_distance(Exynos4210MCTState *s, int32_t id)
+{
+    if (id == -1) {
+        /* no enabled Comparators, choose max distance */
+        return MCT_GT_COUNTER_STEP;
+    }
+    if (s->g_timer.reg.comp[id] - s->g_timer.reg.cnt < MCT_GT_COUNTER_STEP) {
+        return s->g_timer.reg.comp[id] - s->g_timer.reg.cnt;
+    } else {
+        return MCT_GT_COUNTER_STEP;
+    }
+}
+
+/*
+ * Restart global FRC timer
+ */
+static void exynos4210_gfrc_restart(Exynos4210MCTState *s)
+{
+    uint64_t distance;
+
+    exynos4210_gfrc_stop(&s->g_timer);
+
+    s->g_timer.curr_comp = exynos4210_gcomp_find(s);
+
+    distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp);
+
+    if (distance > MCT_GT_COUNTER_STEP || !distance) {
+        distance = MCT_GT_COUNTER_STEP;
+    }
+
+    exynos4210_gfrc_set_count(&s->g_timer, distance);
+    exynos4210_gfrc_start(&s->g_timer);
+}
+
+/*
+ * Raise global timer CMP IRQ
+ */
+static void exynos4210_gcomp_raise_irq(void *opaque, uint32_t id)
+{
+    Exynos4210MCTGT *s = opaque;
+
+    /* If CSTAT is pending and IRQ is enabled */
+    if ((s->reg.int_cstat & G_INT_CSTAT_COMP(id)) &&
+            (s->reg.int_enb & G_INT_ENABLE(id))) {
+        DPRINTF("gcmp timer[%d] IRQ\n", id);
+        qemu_irq_raise(s->irq[id]);
+    }
+}
+
+/*
+ * Lower global timer CMP IRQ
+ */
+static void exynos4210_gcomp_lower_irq(void *opaque, uint32_t id)
+{
+    Exynos4210MCTGT *s = opaque;
+    qemu_irq_lower(s->irq[id]);
+}
+
+/*
+ * Global timer FRC event handler.
+ * Each event occurs when internal counter reaches counter + MCT_GT_COUNTER_STEP
+ * Every time we arm global FRC timer to count for MCT_GT_COUNTER_STEP value
+ */
+static void exynos4210_gfrc_event(void *opaque)
+{
+    Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
+    int i;
+    uint64_t distance;
+
+    DPRINTF("\n");
+
+    s->g_timer.reg.cnt += s->g_timer.count;
+
+    /* Process all comparators */
+    for (i = 0; i < MCT_GT_CMP_NUM; i++) {
+
+        if (s->g_timer.reg.cnt == s->g_timer.reg.comp[i]) {
+            /* reached nearest comparator */
+
+            s->g_timer.reg.int_cstat |= G_INT_CSTAT_COMP(i);
+
+            /* Auto increment */
+            if (s->g_timer.reg.tcon & G_TCON_AUTO_ICREMENT(i)) {
+                s->g_timer.reg.comp[i] += s->g_timer.reg.comp_add_incr[i];
+            }
+
+            /* IRQ */
+            exynos4210_gcomp_raise_irq(&s->g_timer, i);
+        }
+    }
+
+    /* Reload FRC to reach nearest comparator */
+    s->g_timer.curr_comp = exynos4210_gcomp_find(s);
+    distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp);
+    if (distance > MCT_GT_COUNTER_STEP) {
+        distance = MCT_GT_COUNTER_STEP;
+    }
+    exynos4210_gfrc_set_count(&s->g_timer, distance);
+
+    exynos4210_gfrc_start(&s->g_timer);
+
+    return;
+}
+
+/*
+ * Get counter of FRC local timer.
+ */
+static uint64_t exynos4210_lfrc_get_count(Exynos4210MCTLT *s)
+{
+    return ptimer_get_count(s->ptimer_frc);
+}
+
+/*
+ * Set counter of FRC local timer.
+ */
+static void exynos4210_lfrc_update_count(Exynos4210MCTLT *s)
+{
+    if (!s->reg.cnt[L_REG_CNT_FRCCNTB]) {
+        ptimer_set_count(s->ptimer_frc, MCT_LT_COUNTER_STEP);
+    } else {
+        ptimer_set_count(s->ptimer_frc, s->reg.cnt[L_REG_CNT_FRCCNTB]);
+    }
+}
+
+/*
+ * Start local FRC timer
+ */
+static void exynos4210_lfrc_start(Exynos4210MCTLT *s)
+{
+    ptimer_run(s->ptimer_frc, 1);
+}
+
+/*
+ * Stop local FRC timer
+ */
+static void exynos4210_lfrc_stop(Exynos4210MCTLT *s)
+{
+    ptimer_stop(s->ptimer_frc);
+}
+
+/*
+ * Local timer free running counter tick handler
+ */
+static void exynos4210_lfrc_event(void *opaque)
+{
+    Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque;
+
+    /* local frc expired */
+
+    DPRINTF("\n");
+
+    s->reg.int_cstat |= L_INT_CSTAT_FRCCNT;
+
+    /* update frc counter */
+    exynos4210_lfrc_update_count(s);
+
+    /* raise irq */
+    if (s->reg.int_enb & L_INT_INTENB_FRCEIE) {
+        qemu_irq_raise(s->irq);
+    }
+
+    /*  we reached here, this means that timer is enabled */
+    exynos4210_lfrc_start(s);
+}
+
+static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s);
+static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s);
+static void exynos4210_ltick_recalc_count(struct tick_timer *s);
+
+/*
+ * Action on enabling local tick int timer
+ */
+static void exynos4210_ltick_int_start(struct tick_timer *s)
+{
+    if (!s->int_run) {
+        s->int_run = 1;
+    }
+}
+
+/*
+ * Action on disabling local tick int timer
+ */
+static void exynos4210_ltick_int_stop(struct tick_timer *s)
+{
+    if (s->int_run) {
+        s->last_icnto = exynos4210_ltick_int_get_cnto(s);
+        s->int_run = 0;
+    }
+}
+
+/*
+ * Get count for INT timer
+ */
+static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s)
+{
+    uint32_t icnto;
+    uint64_t remain;
+    uint64_t count;
+    uint64_t counted;
+    uint64_t cur_progress;
+
+    count = ptimer_get_count(s->ptimer_tick);
+    if (count) {
+        /* timer is still counting, called not from event */
+        counted = s->count - ptimer_get_count(s->ptimer_tick);
+        cur_progress = s->progress + counted;
+    } else {
+        /* timer expired earlier */
+        cur_progress = s->progress;
+    }
+
+    remain = s->distance - cur_progress;
+
+    if (!s->int_run) {
+        /* INT is stopped. */
+        icnto = s->last_icnto;
+    } else {
+        /* Both are counting */
+        icnto = remain / s->tcntb;
+    }
+
+    return icnto;
+}
+
+/*
+ * Start local tick cnt timer.
+ */
+static void exynos4210_ltick_cnt_start(struct tick_timer *s)
+{
+    if (!s->cnt_run) {
+
+        exynos4210_ltick_recalc_count(s);
+        ptimer_set_count(s->ptimer_tick, s->count);
+        ptimer_run(s->ptimer_tick, 1);
+
+        s->cnt_run = 1;
+    }
+}
+
+/*
+ * Stop local tick cnt timer.
+ */
+static void exynos4210_ltick_cnt_stop(struct tick_timer *s)
+{
+    if (s->cnt_run) {
+
+        s->last_tcnto = exynos4210_ltick_cnt_get_cnto(s);
+
+        if (s->int_run) {
+            exynos4210_ltick_int_stop(s);
+        }
+
+        ptimer_stop(s->ptimer_tick);
+
+        s->cnt_run = 0;
+    }
+}
+
+/*
+ * Get counter for CNT timer
+ */
+static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s)
+{
+    uint32_t tcnto;
+    uint32_t icnto;
+    uint64_t remain;
+    uint64_t counted;
+    uint64_t count;
+    uint64_t cur_progress;
+
+    count = ptimer_get_count(s->ptimer_tick);
+    if (count) {
+        /* timer is still counting, called not from event */
+        counted = s->count - ptimer_get_count(s->ptimer_tick);
+        cur_progress = s->progress + counted;
+    } else {
+        /* timer expired earlier */
+        cur_progress = s->progress;
+    }
+
+    remain = s->distance - cur_progress;
+
+    if (!s->cnt_run) {
+        /* Both are stopped. */
+        tcnto = s->last_tcnto;
+    } else if (!s->int_run) {
+        /* INT counter is stopped, progress is by CNT timer */
+        tcnto = remain % s->tcntb;
+    } else {
+        /* Both are counting */
+        icnto = remain / s->tcntb;
+        if (icnto) {
+            tcnto = remain % (icnto * s->tcntb);
+        } else {
+            tcnto = remain % s->tcntb;
+        }
+    }
+
+    return tcnto;
+}
+
+/*
+ * Set new values of counters for CNT and INT timers
+ */
+static void exynos4210_ltick_set_cntb(struct tick_timer *s, uint32_t new_cnt,
+        uint32_t new_int)
+{
+    uint32_t cnt_stopped = 0;
+    uint32_t int_stopped = 0;
+
+    if (s->cnt_run) {
+        exynos4210_ltick_cnt_stop(s);
+        cnt_stopped = 1;
+    }
+
+    if (s->int_run) {
+        exynos4210_ltick_int_stop(s);
+        int_stopped = 1;
+    }
+
+    s->tcntb = new_cnt + 1;
+    s->icntb = new_int + 1;
+
+    if (cnt_stopped) {
+        exynos4210_ltick_cnt_start(s);
+    }
+    if (int_stopped) {
+        exynos4210_ltick_int_start(s);
+    }
+
+}
+
+/*
+ * Calculate new counter value for tick timer
+ */
+static void exynos4210_ltick_recalc_count(struct tick_timer *s)
+{
+    uint64_t to_count;
+
+    if ((s->cnt_run && s->last_tcnto) || (s->int_run && s->last_icnto)) {
+        /*
+         * one or both timers run and not counted to the end;
+         * distance is not passed, recalculate with last_tcnto * last_icnto
+         */
+
+        if (s->last_tcnto) {
+            to_count = s->last_tcnto * s->last_icnto;
+        } else {
+            to_count = s->last_icnto;
+        }
+    } else {
+        /* distance is passed, recalculate with tcnto * icnto */
+        if (s->icntb) {
+            s->distance = s->tcntb * s->icntb;
+        } else {
+            s->distance = s->tcntb;
+        }
+
+        to_count = s->distance;
+        s->progress = 0;
+    }
+
+    if (to_count > MCT_LT_COUNTER_STEP) {
+        /* count by step */
+        s->count = MCT_LT_COUNTER_STEP;
+    } else {
+        s->count = to_count;
+    }
+}
+
+/*
+ * Initialize tick_timer
+ */
+static void exynos4210_ltick_timer_init(struct tick_timer *s)
+{
+    exynos4210_ltick_int_stop(s);
+    exynos4210_ltick_cnt_stop(s);
+
+    s->count = 0;
+    s->distance = 0;
+    s->progress = 0;
+    s->icntb = 0;
+    s->tcntb = 0;
+}
+
+/*
+ * tick_timer event.
+ * Raises when abstract tick_timer expires.
+ */
+static void exynos4210_ltick_timer_event(struct tick_timer *s)
+{
+    s->progress += s->count;
+}
+
+/*
+ * Local timer tick counter handler.
+ * Don't use reloaded timers. If timer counter = zero
+ * then handler called but after handler finished no
+ * timer reload occurs.
+ */
+static void exynos4210_ltick_event(void *opaque)
+{
+    Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque;
+    uint32_t tcnto;
+    uint32_t icnto;
+#ifdef DEBUG_MCT
+    static uint64_t time1[2] = {0};
+    static uint64_t time2[2] = {0};
+#endif
+
+    /* Call tick_timer event handler, it will update it's tcntb and icntb */
+    exynos4210_ltick_timer_event(&s->tick_timer);
+
+    /* get tick_timer cnt */
+    tcnto = exynos4210_ltick_cnt_get_cnto(&s->tick_timer);
+
+    /* get tick_timer int */
+    icnto = exynos4210_ltick_int_get_cnto(&s->tick_timer);
+
+    /* raise IRQ if needed */
+    if (!icnto && s->reg.tcon & L_TCON_INT_START) {
+        /* INT counter enabled and expired */
+
+        s->reg.int_cstat |= L_INT_CSTAT_INTCNT;
+
+        /* raise interrupt if enabled */
+        if (s->reg.int_enb & L_INT_INTENB_ICNTEIE) {
+#ifdef DEBUG_MCT
+            time2[s->id] = qemu_get_clock_ns(vm_clock);
+            DPRINTF("local timer[%d] IRQ: %llx\n", s->id,
+                    time2[s->id] - time1[s->id]);
+            time1[s->id] = time2[s->id];
+#endif
+            qemu_irq_raise(s->irq);
+        }
+
+        /* reload ICNTB */
+        if (s->reg.tcon & L_TCON_INTERVAL_MODE) {
+            exynos4210_ltick_set_cntb(&s->tick_timer,
+                    s->reg.cnt[L_REG_CNT_TCNTB],
+                    s->reg.cnt[L_REG_CNT_ICNTB]);
+        }
+    } else {
+        /* reload TCNTB */
+        if (!tcnto) {
+            exynos4210_ltick_set_cntb(&s->tick_timer,
+                    s->reg.cnt[L_REG_CNT_TCNTB],
+                    icnto);
+        }
+    }
+
+    /* start tick_timer cnt */
+    exynos4210_ltick_cnt_start(&s->tick_timer);
+
+    /* start tick_timer int */
+    exynos4210_ltick_int_start(&s->tick_timer);
+}
+
+/* update timer frequency */
+static void exynos4210_mct_update_freq(Exynos4210MCTState *s)
+{
+    uint32_t freq = s->freq;
+    s->freq = 24000000 /
+            ((MCT_CFG_GET_PRESCALER(s->reg_mct_cfg)+1) *
+                    MCT_CFG_GET_DIVIDER(s->reg_mct_cfg));
+
+    if (freq != s->freq) {
+        DPRINTF("freq=%dHz\n", s->freq);
+
+        /* global timer */
+        ptimer_set_freq(s->g_timer.ptimer_frc, s->freq);
+
+        /* local timer */
+        ptimer_set_freq(s->l_timer[0].tick_timer.ptimer_tick, s->freq);
+        ptimer_set_freq(s->l_timer[0].ptimer_frc, s->freq);
+        ptimer_set_freq(s->l_timer[1].tick_timer.ptimer_tick, s->freq);
+        ptimer_set_freq(s->l_timer[1].ptimer_frc, s->freq);
+    }
+}
+
+/* set defaul_timer values for all fields */
+static void exynos4210_mct_reset(DeviceState *d)
+{
+    Exynos4210MCTState *s = (Exynos4210MCTState *)d;
+    uint32_t i;
+
+    s->reg_mct_cfg = 0;
+
+    /* global timer */
+    memset(&s->g_timer.reg, 0, sizeof(s->g_timer.reg));
+    exynos4210_gfrc_stop(&s->g_timer);
+
+    /* local timer */
+    memset(s->l_timer[0].reg.cnt, 0, sizeof(s->l_timer[0].reg.cnt));
+    memset(s->l_timer[1].reg.cnt, 0, sizeof(s->l_timer[1].reg.cnt));
+    for (i = 0; i < 2; i++) {
+        s->l_timer[i].reg.int_cstat = 0;
+        s->l_timer[i].reg.int_enb = 0;
+        s->l_timer[i].reg.tcon = 0;
+        s->l_timer[i].reg.wstat = 0;
+        s->l_timer[i].tick_timer.count = 0;
+        s->l_timer[i].tick_timer.distance = 0;
+        s->l_timer[i].tick_timer.progress = 0;
+        ptimer_stop(s->l_timer[i].ptimer_frc);
+
+        exynos4210_ltick_timer_init(&s->l_timer[i].tick_timer);
+    }
+
+    exynos4210_mct_update_freq(s);
+
+}
+
+/* Multi Core Timer read */
+static uint64_t exynos4210_mct_read(void *opaque, target_phys_addr_t offset,
+        unsigned size)
+{
+    Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
+    int index;
+    int shift;
+    uint64_t count;
+    uint32_t value;
+    int lt_i;
+
+    switch (offset) {
+
+    case MCT_CFG:
+        value = s->reg_mct_cfg;
+        break;
+
+    case G_CNT_L: case G_CNT_U:
+        shift = 8 * (offset & 0x4);
+        count = exynos4210_gfrc_get_count(&s->g_timer);
+        value = UINT32_MAX & (count >> shift);
+        DPRINTF("read FRC=0x%llx\n", count);
+        break;
+
+    case G_CNT_WSTAT:
+        value = s->g_timer.reg.cnt_wstat;
+        break;
+
+    case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3):
+    case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3):
+    index = GET_G_COMP_IDX(offset);
+    shift = 8 * (offset & 0x4);
+    value = UINT32_MAX & (s->g_timer.reg.comp[index] >> shift);
+    break;
+
+    case G_TCON:
+        value = s->g_timer.reg.tcon;
+        break;
+
+    case G_INT_CSTAT:
+        value = s->g_timer.reg.int_cstat;
+        break;
+
+    case G_INT_ENB:
+        value = s->g_timer.reg.int_enb;
+        break;
+        break;
+    case G_WSTAT:
+        value = s->g_timer.reg.wstat;
+        break;
+
+    case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR:
+    case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR:
+        value = s->g_timer.reg.comp_add_incr[GET_G_COMP_ADD_INCR_IDX(offset)];
+        break;
+
+        /* Local timers */
+    case L0_TCNTB: case L0_ICNTB: case L0_FRCNTB:
+    case L1_TCNTB: case L1_ICNTB: case L1_FRCNTB:
+        lt_i = GET_L_TIMER_IDX(offset);
+        index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
+        value = s->l_timer[lt_i].reg.cnt[index];
+        break;
+
+    case L0_TCNTO: case L1_TCNTO:
+        lt_i = GET_L_TIMER_IDX(offset);
+
+        value = exynos4210_ltick_cnt_get_cnto(&s->l_timer[lt_i].tick_timer);
+        DPRINTF("local timer[%d] read TCNTO %x\n", lt_i, value);
+        break;
+
+    case L0_ICNTO: case L1_ICNTO:
+        lt_i = GET_L_TIMER_IDX(offset);
+
+        value = exynos4210_ltick_int_get_cnto(&s->l_timer[lt_i].tick_timer);
+        DPRINTF("local timer[%d] read ICNTO %x\n", lt_i, value);
+        break;
+
+    case L0_FRCNTO: case L1_FRCNTO:
+        lt_i = GET_L_TIMER_IDX(offset);
+
+        value = exynos4210_lfrc_get_count(&s->l_timer[lt_i]);
+
+        break;
+
+    case L0_TCON: case L1_TCON:
+        lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
+        value = s->l_timer[lt_i].reg.tcon;
+        break;
+
+    case L0_INT_CSTAT: case L1_INT_CSTAT:
+        lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
+        value = s->l_timer[lt_i].reg.int_cstat;
+        break;
+
+    case L0_INT_ENB: case L1_INT_ENB:
+        lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
+        value = s->l_timer[lt_i].reg.int_enb;
+        break;
+
+    case L0_WSTAT: case L1_WSTAT:
+        lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100;
+        value = s->l_timer[lt_i].reg.wstat;
+        break;
+
+    default:
+        hw_error("exynos4210.mct: bad read offset "
+                TARGET_FMT_plx "\n", offset);
+        break;
+    }
+    return value;
+}
+
+/* MCT write */
+static void exynos4210_mct_write(void *opaque, target_phys_addr_t offset,
+        uint64_t value, unsigned size)
+{
+    Exynos4210MCTState *s = (Exynos4210MCTState *)opaque;
+    int index;  /* index in buffer which represents register set */
+    int shift;
+    int lt_i;
+    uint64_t new_frc;
+    uint32_t i;
+    uint32_t old_val;
+#ifdef DEBUG_MCT
+    static uint32_t icntb_max[2] = {0};
+    static uint32_t icntb_min[2] = {UINT32_MAX, UINT32_MAX};
+    static uint32_t tcntb_max[2] = {0};
+    static uint32_t tcntb_min[2] = {UINT32_MAX, UINT32_MAX};
+#endif
+
+    new_frc = s->g_timer.reg.cnt;
+
+    switch (offset) {
+
+    case MCT_CFG:
+        s->reg_mct_cfg = value;
+        exynos4210_mct_update_freq(s);
+        break;
+
+    case G_CNT_L:
+    case G_CNT_U:
+        if (offset == G_CNT_L) {
+
+            DPRINTF("global timer write to reg.cntl %llx\n", value);
+
+            new_frc = (s->g_timer.reg.cnt & (uint64_t)UINT32_MAX << 32) + value;
+            s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_L;
+        }
+        if (offset == G_CNT_U) {
+
+            DPRINTF("global timer write to reg.cntu %llx\n", value);
+
+            new_frc = (s->g_timer.reg.cnt & UINT32_MAX) +
+                    ((uint64_t)value << 32);
+            s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_U;
+        }
+
+        s->g_timer.reg.cnt = new_frc;
+        exynos4210_gfrc_restart(s);
+        break;
+
+    case G_CNT_WSTAT:
+        s->g_timer.reg.cnt_wstat &= ~(value);
+        break;
+
+    case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3):
+    case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3):
+    index = GET_G_COMP_IDX(offset);
+    shift = 8 * (offset & 0x4);
+    s->g_timer.reg.comp[index] =
+            (s->g_timer.reg.comp[index] &
+            (((uint64_t)UINT32_MAX << 32) >> shift)) +
+            (value << shift);
+
+    DPRINTF("comparator %d write 0x%llx val << %d\n", index, value, shift);
+
+    if (offset&0x4) {
+        s->g_timer.reg.wstat |= G_WSTAT_COMP_U(index);
+    } else {
+        s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index);
+    }
+
+    exynos4210_gfrc_restart(s);
+    break;
+
+    case G_TCON:
+        old_val = s->g_timer.reg.tcon;
+        s->g_timer.reg.tcon = value;
+        s->g_timer.reg.wstat |= G_WSTAT_TCON_WRITE;
+
+        DPRINTF("global timer write to reg.g_tcon %llx\n", value);
+
+        /* Start FRC if transition from disabled to enabled */
+        if ((value & G_TCON_TIMER_ENABLE) > (old_val &
+                G_TCON_TIMER_ENABLE)) {
+            exynos4210_gfrc_start(&s->g_timer);
+        }
+        if ((value & G_TCON_TIMER_ENABLE) < (old_val &
+                G_TCON_TIMER_ENABLE)) {
+            exynos4210_gfrc_stop(&s->g_timer);
+        }
+
+        /* Start CMP if transition from disabled to enabled */
+        for (i = 0; i < MCT_GT_CMP_NUM; i++) {
+            if ((value & G_TCON_COMP_ENABLE(i)) != (old_val &
+                    G_TCON_COMP_ENABLE(i))) {
+                exynos4210_gfrc_restart(s);
+            }
+        }
+        break;
+
+    case G_INT_CSTAT:
+        s->g_timer.reg.int_cstat &= ~(value);
+        for (i = 0; i < MCT_GT_CMP_NUM; i++) {
+            if (value & G_INT_CSTAT_COMP(i)) {
+                exynos4210_gcomp_lower_irq(&s->g_timer, i);
+            }
+        }
+        break;
+
+    case G_INT_ENB:
+
+        /* Raise IRQ if transition from disabled to enabled and CSTAT pending */
+        for (i = 0; i < MCT_GT_CMP_NUM; i++) {
+            if ((value & G_INT_ENABLE(i)) > (s->g_timer.reg.tcon &
+                    G_INT_ENABLE(i))) {
+                if (s->g_timer.reg.int_cstat & G_INT_CSTAT_COMP(i)) {
+                    exynos4210_gcomp_raise_irq(&s->g_timer, i);
+                }
+            }
+
+            if ((value & G_INT_ENABLE(i)) < (s->g_timer.reg.tcon &
+                    G_INT_ENABLE(i))) {
+                exynos4210_gcomp_lower_irq(&s->g_timer, i);
+            }
+        }
+
+        DPRINTF("global timer INT enable %llx\n", value);
+        s->g_timer.reg.int_enb = value;
+        break;
+
+    case G_WSTAT:
+        s->g_timer.reg.wstat &= ~(value);
+        break;
+
+    case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR:
+    case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR:
+        index = GET_G_COMP_ADD_INCR_IDX(offset);
+        s->g_timer.reg.comp_add_incr[index] = value;
+        s->g_timer.reg.wstat |= G_WSTAT_COMP_ADDINCR(index);
+        break;
+
+        /* Local timers */
+    case L0_TCON: case L1_TCON:
+        lt_i = GET_L_TIMER_IDX(offset);
+        old_val = s->l_timer[lt_i].reg.tcon;
+
+        s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCON_WRITE;
+        s->l_timer[lt_i].reg.tcon = value;
+
+        /* Stop local CNT */
+        if ((value & L_TCON_TICK_START) <
+                (old_val & L_TCON_TICK_START)) {
+            DPRINTF("local timer[%d] stop cnt\n", lt_i);
+            exynos4210_ltick_cnt_stop(&s->l_timer[lt_i].tick_timer);
+        }
+
+        /* Stop local INT */
+        if ((value & L_TCON_INT_START) <
+                (old_val & L_TCON_INT_START)) {
+            DPRINTF("local timer[%d] stop int\n", lt_i);
+            exynos4210_ltick_int_stop(&s->l_timer[lt_i].tick_timer);
+        }
+
+        /* Start local CNT */
+        if ((value & L_TCON_TICK_START) >
+        (old_val & L_TCON_TICK_START)) {
+            DPRINTF("local timer[%d] start cnt\n", lt_i);
+            exynos4210_ltick_cnt_start(&s->l_timer[lt_i].tick_timer);
+        }
+
+        /* Start local INT */
+        if ((value & L_TCON_INT_START) >
+        (old_val & L_TCON_INT_START)) {
+            DPRINTF("local timer[%d] start int\n", lt_i);
+            exynos4210_ltick_int_start(&s->l_timer[lt_i].tick_timer);
+        }
+
+        /* Start or Stop local FRC if TCON changed */
+        if ((value & L_TCON_FRC_START) >
+        (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) {
+            DPRINTF("local timer[%d] start frc\n", lt_i);
+            exynos4210_lfrc_start(&s->l_timer[lt_i]);
+        }
+        if ((value & L_TCON_FRC_START) <
+                (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) {
+            DPRINTF("local timer[%d] stop frc\n", lt_i);
+            exynos4210_lfrc_stop(&s->l_timer[lt_i]);
+        }
+        break;
+
+    case L0_TCNTB: case L1_TCNTB:
+
+        lt_i = GET_L_TIMER_IDX(offset);
+        index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
+
+        /*
+         * TCNTB is updated to internal register only after CNT expired.
+         * Due to this we should reload timer to nearest moment when CNT is
+         * expired and then in event handler update tcntb to new TCNTB value.
+         */
+        exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer, value,
+                s->l_timer[lt_i].tick_timer.icntb);
+
+        s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCNTB_WRITE;
+        s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] = value;
+
+#ifdef DEBUG_MCT
+        if (tcntb_min[lt_i] > value) {
+            tcntb_min[lt_i] = value;
+        }
+        if (tcntb_max[lt_i] < value) {
+            tcntb_max[lt_i] = value;
+        }
+        DPRINTF("local timer[%d] TCNTB write %llx; max=%x, min=%x\n",
+                lt_i, value, tcntb_max[lt_i], tcntb_min[lt_i]);
+#endif
+        break;
+
+    case L0_ICNTB: case L1_ICNTB:
+
+        lt_i = GET_L_TIMER_IDX(offset);
+        index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
+
+        s->l_timer[lt_i].reg.wstat |= L_WSTAT_ICNTB_WRITE;
+        s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = value &
+                ~L_ICNTB_MANUAL_UPDATE;
+
+        /*
+         * We need to avoid too small values for TCNTB*ICNTB. If not, IRQ event
+         * could raise too fast disallowing QEMU to execute target code.
+         */
+        if (s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] *
+            s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] < MCT_LT_CNT_LOW_LIMIT) {
+            if (!s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB]) {
+                s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] =
+                        MCT_LT_CNT_LOW_LIMIT;
+            } else {
+                s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] =
+                        MCT_LT_CNT_LOW_LIMIT /
+                        s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB];
+            }
+        }
+
+        if (value & L_ICNTB_MANUAL_UPDATE) {
+            exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer,
+                    s->l_timer[lt_i].tick_timer.tcntb,
+                    s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB]);
+        }
+
+#ifdef DEBUG_MCT
+        if (icntb_min[lt_i] > value) {
+            icntb_min[lt_i] = value;
+        }
+        if (icntb_max[lt_i] < value) {
+            icntb_max[lt_i] = value;
+        }
+DPRINTF("local timer[%d] ICNTB write %llx; max=%x, min=%x\n\n",
+        lt_i, value, icntb_max[lt_i], icntb_min[lt_i]);
+#endif
+break;
+
+    case L0_FRCNTB: case L1_FRCNTB:
+
+        lt_i = GET_L_TIMER_IDX(offset);
+        index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
+
+        DPRINTF("local timer[%d] FRCNTB write %llx\n", lt_i, value);
+
+        s->l_timer[lt_i].reg.wstat |= L_WSTAT_FRCCNTB_WRITE;
+        s->l_timer[lt_i].reg.cnt[L_REG_CNT_FRCCNTB] = value;
+
+        break;
+
+    case L0_TCNTO: case L1_TCNTO:
+    case L0_ICNTO: case L1_ICNTO:
+    case L0_FRCNTO: case L1_FRCNTO:
+        fprintf(stderr, "\n[exynos4210.mct: write to RO register "
+                TARGET_FMT_plx "]\n\n", offset);
+        break;
+
+    case L0_INT_CSTAT: case L1_INT_CSTAT:
+        lt_i = GET_L_TIMER_IDX(offset);
+
+        DPRINTF("local timer[%d] CSTAT write %llx\n", lt_i, value);
+
+        s->l_timer[lt_i].reg.int_cstat &= ~value;
+        if (!s->l_timer[lt_i].reg.int_cstat) {
+            qemu_irq_lower(s->l_timer[lt_i].irq);
+        }
+        break;
+
+    case L0_INT_ENB: case L1_INT_ENB:
+        lt_i = GET_L_TIMER_IDX(offset);
+        old_val = s->l_timer[lt_i].reg.int_enb;
+
+        /* Raise Local timer IRQ if cstat is pending */
+        if ((value & L_INT_INTENB_ICNTEIE) > (old_val & L_INT_INTENB_ICNTEIE)) {
+            if (s->l_timer[lt_i].reg.int_cstat & L_INT_CSTAT_INTCNT) {
+                qemu_irq_raise(s->l_timer[lt_i].irq);
+            }
+        }
+
+        s->l_timer[lt_i].reg.int_enb = value;
+
+        break;
+
+    case L0_WSTAT: case L1_WSTAT:
+        lt_i = GET_L_TIMER_IDX(offset);
+
+        s->l_timer[lt_i].reg.wstat &= ~value;
+        break;
+
+    default:
+        hw_error("exynos4210.mct: bad write offset "
+                TARGET_FMT_plx "\n", offset);
+        break;
+    }
+}
+
+static const MemoryRegionOps exynos4210_mct_ops = {
+    .read = exynos4210_mct_read,
+    .write = exynos4210_mct_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/* MCT init */
+static int exynos4210_mct_init(SysBusDevice *dev)
+{
+    int i;
+    Exynos4210MCTState *s = FROM_SYSBUS(Exynos4210MCTState, dev);
+    QEMUBH *bh[2];
+
+    /* Global timer */
+    bh[0] = qemu_bh_new(exynos4210_gfrc_event, s);
+    s->g_timer.ptimer_frc = ptimer_init(bh[0]);
+    memset(&s->g_timer.reg, 0, sizeof(struct gregs));
+
+    /* Local timers */
+    for (i = 0; i < 2; i++) {
+        bh[0] = qemu_bh_new(exynos4210_ltick_event, &s->l_timer[i]);
+        bh[1] = qemu_bh_new(exynos4210_lfrc_event, &s->l_timer[i]);
+        s->l_timer[i].tick_timer.ptimer_tick = ptimer_init(bh[0]);
+        s->l_timer[i].ptimer_frc = ptimer_init(bh[1]);
+        s->l_timer[i].id = i;
+    }
+
+    /* IRQs */
+    for (i = 0; i < MCT_GT_CMP_NUM; i++) {
+        sysbus_init_irq(dev, &s->g_timer.irq[i]);
+    }
+    for (i = 0; i < 2; i++) {
+        sysbus_init_irq(dev, &s->l_timer[i].irq);
+    }
+
+    memory_region_init_io(&s->iomem, &exynos4210_mct_ops, s, "exynos4210-mct",
+            MCT_SFR_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void exynos4210_mct_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = exynos4210_mct_init;
+    dc->reset = exynos4210_mct_reset;
+    dc->vmsd = &vmstate_exynos4210_mct_state;
+}
+
+static TypeInfo exynos4210_mct_info = {
+    .name          = "exynos4210.mct",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210MCTState),
+    .class_init    = exynos4210_mct_class_init,
+};
+
+static void exynos4210_mct_register_types(void)
+{
+    type_register_static(&exynos4210_mct_info);
+}
+
+type_init(exynos4210_mct_register_types)
commit df91b48f64075595e25a269befed5e4fe75501cb
Author: Maksim Kozlov <m.kozlov at samsung.com>
Date:   Thu Feb 16 09:56:05 2012 +0000

    ARM: exynos4210: basic Power Management Unit implementation
    
    Patch adds basic model for Exynos4210 SoC PMU.
    This model implements PMU registers just as a bulk of memory. Currently,
    the only reason this device exists is that secondary CPU boot loader
    uses PMU INFORM5 register as a holding pen.
    
    Signed-off-by: Maksim Kozlov <m.kozlov at samsung.com>
    Signed-off-by: Evgeny Voevodin <e.voevodin at samsung.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/Makefile.target b/Makefile.target
index bbcee06..8a7b4d2 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -346,6 +346,7 @@ obj-arm-y += versatile_pci.o
 obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
 obj-arm-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
 obj-arm-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
+obj-arm-y += exynos4210_pmu.o
 obj-arm-y += arm_l2x0.o
 obj-arm-y += arm_mptimer.o
 obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
diff --git a/hw/exynos4210.c b/hw/exynos4210.c
index 8ebe5df..f922f55 100644
--- a/hw/exynos4210.c
+++ b/hw/exynos4210.c
@@ -52,6 +52,9 @@
 #define EXYNOS4210_EXT_COMBINER_BASE_ADDR   0x10440000
 #define EXYNOS4210_INT_COMBINER_BASE_ADDR   0x10448000
 
+/* PMU SFR base address */
+#define EXYNOS4210_PMU_BASE_ADDR            0x10020000
+
 static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43,
                                     0x09, 0x00, 0x00, 0x00 };
 
@@ -202,6 +205,12 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
     memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR,
             &s->dram0_mem);
 
+   /* PMU.
+    * The only reason of existence at the moment is that secondary CPU boot
+    * loader uses PMU INFORM5 register as a holding pen.
+    */
+    sysbus_create_simple("exynos4210.pmu", EXYNOS4210_PMU_BASE_ADDR, NULL);
+
     /* PWM */
     sysbus_create_varargs("exynos4210.pwm", EXYNOS4210_PWM_BASE_ADDR,
                           s->irq_table[exynos4210_get_irq(22, 0)],
diff --git a/hw/exynos4210_pmu.c b/hw/exynos4210_pmu.c
new file mode 100644
index 0000000..c12d750
--- /dev/null
+++ b/hw/exynos4210_pmu.c
@@ -0,0 +1,499 @@
+/*
+ *  Exynos4210 Power Management Unit (PMU) Emulation
+ *
+ *  Copyright (C) 2011 Samsung Electronics Co Ltd.
+ *    Maksim Kozlov <m.kozlov at samsung.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 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/>.
+ */
+
+/*
+ * This model implements PMU registers just as a bulk of memory. Currently,
+ * the only reason this device exists is that secondary CPU boot loader
+ * uses PMU INFORM5 register as a holding pen.
+ */
+
+#include "sysbus.h"
+
+#ifndef DEBUG_PMU
+#define DEBUG_PMU           0
+#endif
+
+#ifndef DEBUG_PMU_EXTEND
+#define DEBUG_PMU_EXTEND    0
+#endif
+
+#if DEBUG_PMU
+#define  PRINT_DEBUG(fmt, args...)  \
+        do { \
+            fprintf(stderr, "  [%s:%d]   "fmt, __func__, __LINE__, ##args); \
+        } while (0)
+
+#if DEBUG_PMU_EXTEND
+#define  PRINT_DEBUG_EXTEND(fmt, args...) \
+        do { \
+            fprintf(stderr, "  [%s:%d]   "fmt, __func__, __LINE__, ##args); \
+        } while (0)
+#else
+#define  PRINT_DEBUG_EXTEND(fmt, args...)  do {} while (0)
+#endif /* EXTEND */
+
+#else
+#define  PRINT_DEBUG(fmt, args...)   do {} while (0)
+#define  PRINT_DEBUG_EXTEND(fmt, args...)  do {} while (0)
+#endif
+
+/*
+ *  Offsets for PMU registers
+ */
+#define OM_STAT                  0x0000 /* OM status register */
+#define RTC_CLKO_SEL             0x000C /* Controls RTCCLKOUT */
+#define GNSS_RTC_OUT_CTRL        0x0010 /* Controls GNSS_RTC_OUT */
+/* Decides whether system-level low-power mode is used. */
+#define SYSTEM_POWER_DOWN_CTRL   0x0200
+/* Sets control options for CENTRAL_SEQ */
+#define SYSTEM_POWER_DOWN_OPTION 0x0208
+#define SWRESET                  0x0400 /* Generate software reset */
+#define RST_STAT                 0x0404 /* Reset status register */
+#define WAKEUP_STAT              0x0600 /* Wakeup status register  */
+#define EINT_WAKEUP_MASK         0x0604 /* Configure External INTerrupt mask */
+#define WAKEUP_MASK              0x0608 /* Configure wakeup source mask */
+#define HDMI_PHY_CONTROL         0x0700 /* HDMI PHY control register */
+#define USBDEVICE_PHY_CONTROL    0x0704 /* USB Device PHY control register */
+#define USBHOST_PHY_CONTROL      0x0708 /* USB HOST PHY control register */
+#define DAC_PHY_CONTROL          0x070C /* DAC control register  */
+#define MIPI_PHY0_CONTROL        0x0710 /* MIPI PHY control register */
+#define MIPI_PHY1_CONTROL        0x0714 /* MIPI PHY control register */
+#define ADC_PHY_CONTROL          0x0718 /* TS-ADC control register */
+#define PCIe_PHY_CONTROL         0x071C /* TS-PCIe control register */
+#define SATA_PHY_CONTROL         0x0720 /* TS-SATA control register */
+#define INFORM0                  0x0800 /* Information register 0  */
+#define INFORM1                  0x0804 /* Information register 1  */
+#define INFORM2                  0x0808 /* Information register 2  */
+#define INFORM3                  0x080C /* Information register 3  */
+#define INFORM4                  0x0810 /* Information register 4  */
+#define INFORM5                  0x0814 /* Information register 5  */
+#define INFORM6                  0x0818 /* Information register 6  */
+#define INFORM7                  0x081C /* Information register 7  */
+#define PMU_DEBUG                0x0A00 /* PMU debug register */
+/* Registers to set system-level low-power option */
+#define ARM_CORE0_SYS_PWR_REG              0x1000
+#define ARM_CORE1_SYS_PWR_REG              0x1010
+#define ARM_COMMON_SYS_PWR_REG             0x1080
+#define ARM_CPU_L2_0_SYS_PWR_REG           0x10C0
+#define ARM_CPU_L2_1_SYS_PWR_REG           0x10C4
+#define CMU_ACLKSTOP_SYS_PWR_REG           0x1100
+#define CMU_SCLKSTOP_SYS_PWR_REG           0x1104
+#define CMU_RESET_SYS_PWR_REG              0x110C
+#define APLL_SYSCLK_SYS_PWR_REG            0x1120
+#define MPLL_SYSCLK_SYS_PWR_REG            0x1124
+#define VPLL_SYSCLK_SYS_PWR_REG            0x1128
+#define EPLL_SYSCLK_SYS_PWR_REG            0x112C
+#define CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG  0x1138
+#define CMU_RESET_GPS_ALIVE_SYS_PWR_REG    0x113C
+#define CMU_CLKSTOP_CAM_SYS_PWR_REG        0x1140
+#define CMU_CLKSTOP_TV_SYS_PWR_REG         0x1144
+#define CMU_CLKSTOP_MFC_SYS_PWR_REG        0x1148
+#define CMU_CLKSTOP_G3D_SYS_PWR_REG        0x114C
+#define CMU_CLKSTOP_LCD0_SYS_PWR_REG       0x1150
+#define CMU_CLKSTOP_LCD1_SYS_PWR_REG       0x1154
+#define CMU_CLKSTOP_MAUDIO_SYS_PWR_REG     0x1158
+#define CMU_CLKSTOP_GPS_SYS_PWR_REG        0x115C
+#define CMU_RESET_CAM_SYS_PWR_REG          0x1160
+#define CMU_RESET_TV_SYS_PWR_REG           0x1164
+#define CMU_RESET_MFC_SYS_PWR_REG          0x1168
+#define CMU_RESET_G3D_SYS_PWR_REG          0x116C
+#define CMU_RESET_LCD0_SYS_PWR_REG         0x1170
+#define CMU_RESET_LCD1_SYS_PWR_REG         0x1174
+#define CMU_RESET_MAUDIO_SYS_PWR_REG       0x1178
+#define CMU_RESET_GPS_SYS_PWR_REG          0x117C
+#define TOP_BUS_SYS_PWR_REG                0x1180
+#define TOP_RETENTION_SYS_PWR_REG          0x1184
+#define TOP_PWR_SYS_PWR_REG                0x1188
+#define LOGIC_RESET_SYS_PWR_REG            0x11A0
+#define OneNANDXL_MEM_SYS_PWR_REG          0x11C0
+#define MODEMIF_MEM_SYS_PWR_REG            0x11C4
+#define USBDEVICE_MEM_SYS_PWR_REG          0x11CC
+#define SDMMC_MEM_SYS_PWR_REG              0x11D0
+#define CSSYS_MEM_SYS_PWR_REG              0x11D4
+#define SECSS_MEM_SYS_PWR_REG              0x11D8
+#define PCIe_MEM_SYS_PWR_REG               0x11E0
+#define SATA_MEM_SYS_PWR_REG               0x11E4
+#define PAD_RETENTION_DRAM_SYS_PWR_REG     0x1200
+#define PAD_RETENTION_MAUDIO_SYS_PWR_REG   0x1204
+#define PAD_RETENTION_GPIO_SYS_PWR_REG     0x1220
+#define PAD_RETENTION_UART_SYS_PWR_REG     0x1224
+#define PAD_RETENTION_MMCA_SYS_PWR_REG     0x1228
+#define PAD_RETENTION_MMCB_SYS_PWR_REG     0x122C
+#define PAD_RETENTION_EBIA_SYS_PWR_REG     0x1230
+#define PAD_RETENTION_EBIB_SYS_PWR_REG     0x1234
+#define PAD_ISOLATION_SYS_PWR_REG          0x1240
+#define PAD_ALV_SEL_SYS_PWR_REG            0x1260
+#define XUSBXTI_SYS_PWR_REG                0x1280
+#define XXTI_SYS_PWR_REG                   0x1284
+#define EXT_REGULATOR_SYS_PWR_REG          0x12C0
+#define GPIO_MODE_SYS_PWR_REG              0x1300
+#define GPIO_MODE_MAUDIO_SYS_PWR_REG       0x1340
+#define CAM_SYS_PWR_REG                    0x1380
+#define TV_SYS_PWR_REG                     0x1384
+#define MFC_SYS_PWR_REG                    0x1388
+#define G3D_SYS_PWR_REG                    0x138C
+#define LCD0_SYS_PWR_REG                   0x1390
+#define LCD1_SYS_PWR_REG                   0x1394
+#define MAUDIO_SYS_PWR_REG                 0x1398
+#define GPS_SYS_PWR_REG                    0x139C
+#define GPS_ALIVE_SYS_PWR_REG              0x13A0
+#define ARM_CORE0_CONFIGURATION 0x2000 /* Configure power mode of ARM_CORE0 */
+#define ARM_CORE0_STATUS        0x2004 /* Check power mode of ARM_CORE0 */
+#define ARM_CORE0_OPTION        0x2008 /* Sets control options for ARM_CORE0 */
+#define ARM_CORE1_CONFIGURATION 0x2080 /* Configure power mode of ARM_CORE1 */
+#define ARM_CORE1_STATUS        0x2084 /* Check power mode of ARM_CORE1 */
+#define ARM_CORE1_OPTION        0x2088 /* Sets control options for ARM_CORE0 */
+#define ARM_COMMON_OPTION       0x2408 /* Sets control options for ARM_COMMON */
+/* Configure power mode of ARM_CPU_L2_0 */
+#define ARM_CPU_L2_0_CONFIGURATION 0x2600
+#define ARM_CPU_L2_0_STATUS        0x2604 /* Check power mode of ARM_CPU_L2_0 */
+/* Configure power mode of ARM_CPU_L2_1 */
+#define ARM_CPU_L2_1_CONFIGURATION 0x2620
+#define ARM_CPU_L2_1_STATUS        0x2624 /* Check power mode of ARM_CPU_L2_1 */
+/* Sets control options for PAD_RETENTION_MAUDIO */
+#define PAD_RETENTION_MAUDIO_OPTION 0x3028
+/* Sets control options for PAD_RETENTION_GPIO */
+#define PAD_RETENTION_GPIO_OPTION   0x3108
+/* Sets control options for PAD_RETENTION_UART */
+#define PAD_RETENTION_UART_OPTION   0x3128
+/* Sets control options for PAD_RETENTION_MMCA */
+#define PAD_RETENTION_MMCA_OPTION   0x3148
+/* Sets control options for PAD_RETENTION_MMCB */
+#define PAD_RETENTION_MMCB_OPTION   0x3168
+/* Sets control options for PAD_RETENTION_EBIA */
+#define PAD_RETENTION_EBIA_OPTION   0x3188
+/* Sets control options for PAD_RETENTION_EBIB */
+#define PAD_RETENTION_EBIB_OPTION   0x31A8
+#define PS_HOLD_CONTROL         0x330C /* PS_HOLD control register */
+#define XUSBXTI_CONFIGURATION   0x3400 /* Configure the pad of XUSBXTI */
+#define XUSBXTI_STATUS          0x3404 /* Check the pad of XUSBXTI */
+/* Sets time required for XUSBXTI to be stabilized */
+#define XUSBXTI_DURATION        0x341C
+#define XXTI_CONFIGURATION      0x3420 /* Configure the pad of XXTI */
+#define XXTI_STATUS             0x3424 /* Check the pad of XXTI */
+/* Sets time required for XXTI to be stabilized */
+#define XXTI_DURATION           0x343C
+/* Sets time required for EXT_REGULATOR to be stabilized */
+#define EXT_REGULATOR_DURATION  0x361C
+#define CAM_CONFIGURATION       0x3C00 /* Configure power mode of CAM */
+#define CAM_STATUS              0x3C04 /* Check power mode of CAM */
+#define CAM_OPTION              0x3C08 /* Sets control options for CAM */
+#define TV_CONFIGURATION        0x3C20 /* Configure power mode of TV */
+#define TV_STATUS               0x3C24 /* Check power mode of TV */
+#define TV_OPTION               0x3C28 /* Sets control options for TV */
+#define MFC_CONFIGURATION       0x3C40 /* Configure power mode of MFC */
+#define MFC_STATUS              0x3C44 /* Check power mode of MFC */
+#define MFC_OPTION              0x3C48 /* Sets control options for MFC */
+#define G3D_CONFIGURATION       0x3C60 /* Configure power mode of G3D */
+#define G3D_STATUS              0x3C64 /* Check power mode of G3D */
+#define G3D_OPTION              0x3C68 /* Sets control options for G3D */
+#define LCD0_CONFIGURATION      0x3C80 /* Configure power mode of LCD0 */
+#define LCD0_STATUS             0x3C84 /* Check power mode of LCD0 */
+#define LCD0_OPTION             0x3C88 /* Sets control options for LCD0 */
+#define LCD1_CONFIGURATION      0x3CA0 /* Configure power mode of LCD1 */
+#define LCD1_STATUS             0x3CA4 /* Check power mode of LCD1 */
+#define LCD1_OPTION             0x3CA8 /* Sets control options for LCD1 */
+#define GPS_CONFIGURATION       0x3CE0 /* Configure power mode of GPS */
+#define GPS_STATUS              0x3CE4 /* Check power mode of GPS */
+#define GPS_OPTION              0x3CE8 /* Sets control options for GPS */
+#define GPS_ALIVE_CONFIGURATION 0x3D00 /* Configure power mode of GPS */
+#define GPS_ALIVE_STATUS        0x3D04 /* Check power mode of GPS */
+#define GPS_ALIVE_OPTION        0x3D08 /* Sets control options for GPS */
+
+#define EXYNOS4210_PMU_REGS_MEM_SIZE 0x3d0c
+
+typedef struct Exynos4210PmuReg {
+    const char  *name; /* for debug only */
+    uint32_t     offset;
+    uint32_t     reset_value;
+} Exynos4210PmuReg;
+
+static const Exynos4210PmuReg exynos4210_pmu_regs[] = {
+    {"OM_STAT", OM_STAT, 0x00000000},
+    {"RTC_CLKO_SEL", RTC_CLKO_SEL, 0x00000000},
+    {"GNSS_RTC_OUT_CTRL", GNSS_RTC_OUT_CTRL, 0x00000001},
+    {"SYSTEM_POWER_DOWN_CTRL", SYSTEM_POWER_DOWN_CTRL, 0x00010000},
+    {"SYSTEM_POWER_DOWN_OPTION", SYSTEM_POWER_DOWN_OPTION, 0x03030000},
+    {"SWRESET", SWRESET, 0x00000000},
+    {"RST_STAT", RST_STAT, 0x00000000},
+    {"WAKEUP_STAT", WAKEUP_STAT, 0x00000000},
+    {"EINT_WAKEUP_MASK", EINT_WAKEUP_MASK, 0x00000000},
+    {"WAKEUP_MASK", WAKEUP_MASK, 0x00000000},
+    {"HDMI_PHY_CONTROL", HDMI_PHY_CONTROL, 0x00960000},
+    {"USBDEVICE_PHY_CONTROL", USBDEVICE_PHY_CONTROL, 0x00000000},
+    {"USBHOST_PHY_CONTROL", USBHOST_PHY_CONTROL, 0x00000000},
+    {"DAC_PHY_CONTROL", DAC_PHY_CONTROL, 0x00000000},
+    {"MIPI_PHY0_CONTROL", MIPI_PHY0_CONTROL, 0x00000000},
+    {"MIPI_PHY1_CONTROL", MIPI_PHY1_CONTROL, 0x00000000},
+    {"ADC_PHY_CONTROL", ADC_PHY_CONTROL, 0x00000001},
+    {"PCIe_PHY_CONTROL", PCIe_PHY_CONTROL, 0x00000000},
+    {"SATA_PHY_CONTROL", SATA_PHY_CONTROL, 0x00000000},
+    {"INFORM0", INFORM0, 0x00000000},
+    {"INFORM1", INFORM1, 0x00000000},
+    {"INFORM2", INFORM2, 0x00000000},
+    {"INFORM3", INFORM3, 0x00000000},
+    {"INFORM4", INFORM4, 0x00000000},
+    {"INFORM5", INFORM5, 0x00000000},
+    {"INFORM6", INFORM6, 0x00000000},
+    {"INFORM7", INFORM7, 0x00000000},
+    {"PMU_DEBUG", PMU_DEBUG, 0x00000000},
+    {"ARM_CORE0_SYS_PWR_REG", ARM_CORE0_SYS_PWR_REG, 0xFFFFFFFF},
+    {"ARM_CORE1_SYS_PWR_REG", ARM_CORE1_SYS_PWR_REG, 0xFFFFFFFF},
+    {"ARM_COMMON_SYS_PWR_REG", ARM_COMMON_SYS_PWR_REG, 0xFFFFFFFF},
+    {"ARM_CPU_L2_0_SYS_PWR_REG", ARM_CPU_L2_0_SYS_PWR_REG, 0xFFFFFFFF},
+    {"ARM_CPU_L2_1_SYS_PWR_REG", ARM_CPU_L2_1_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_ACLKSTOP_SYS_PWR_REG", CMU_ACLKSTOP_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_SCLKSTOP_SYS_PWR_REG", CMU_SCLKSTOP_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_RESET_SYS_PWR_REG", CMU_RESET_SYS_PWR_REG, 0xFFFFFFFF},
+    {"APLL_SYSCLK_SYS_PWR_REG", APLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF},
+    {"MPLL_SYSCLK_SYS_PWR_REG", MPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF},
+    {"VPLL_SYSCLK_SYS_PWR_REG", VPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF},
+    {"EPLL_SYSCLK_SYS_PWR_REG", EPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG", CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG,
+            0xFFFFFFFF},
+    {"CMU_RESET_GPS_ALIVE_SYS_PWR_REG", CMU_RESET_GPS_ALIVE_SYS_PWR_REG,
+            0xFFFFFFFF},
+    {"CMU_CLKSTOP_CAM_SYS_PWR_REG", CMU_CLKSTOP_CAM_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_CLKSTOP_TV_SYS_PWR_REG", CMU_CLKSTOP_TV_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_CLKSTOP_MFC_SYS_PWR_REG", CMU_CLKSTOP_MFC_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_CLKSTOP_G3D_SYS_PWR_REG", CMU_CLKSTOP_G3D_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_CLKSTOP_LCD0_SYS_PWR_REG", CMU_CLKSTOP_LCD0_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_CLKSTOP_LCD1_SYS_PWR_REG", CMU_CLKSTOP_LCD1_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_CLKSTOP_MAUDIO_SYS_PWR_REG", CMU_CLKSTOP_MAUDIO_SYS_PWR_REG,
+            0xFFFFFFFF},
+    {"CMU_CLKSTOP_GPS_SYS_PWR_REG", CMU_CLKSTOP_GPS_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_RESET_CAM_SYS_PWR_REG", CMU_RESET_CAM_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_RESET_TV_SYS_PWR_REG", CMU_RESET_TV_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_RESET_MFC_SYS_PWR_REG", CMU_RESET_MFC_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_RESET_G3D_SYS_PWR_REG", CMU_RESET_G3D_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_RESET_LCD0_SYS_PWR_REG", CMU_RESET_LCD0_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_RESET_LCD1_SYS_PWR_REG", CMU_RESET_LCD1_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_RESET_MAUDIO_SYS_PWR_REG", CMU_RESET_MAUDIO_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CMU_RESET_GPS_SYS_PWR_REG", CMU_RESET_GPS_SYS_PWR_REG, 0xFFFFFFFF},
+    {"TOP_BUS_SYS_PWR_REG", TOP_BUS_SYS_PWR_REG, 0xFFFFFFFF},
+    {"TOP_RETENTION_SYS_PWR_REG", TOP_RETENTION_SYS_PWR_REG, 0xFFFFFFFF},
+    {"TOP_PWR_SYS_PWR_REG", TOP_PWR_SYS_PWR_REG, 0xFFFFFFFF},
+    {"LOGIC_RESET_SYS_PWR_REG", LOGIC_RESET_SYS_PWR_REG, 0xFFFFFFFF},
+    {"OneNANDXL_MEM_SYS_PWR_REG", OneNANDXL_MEM_SYS_PWR_REG, 0xFFFFFFFF},
+    {"MODEMIF_MEM_SYS_PWR_REG", MODEMIF_MEM_SYS_PWR_REG, 0xFFFFFFFF},
+    {"USBDEVICE_MEM_SYS_PWR_REG", USBDEVICE_MEM_SYS_PWR_REG, 0xFFFFFFFF},
+    {"SDMMC_MEM_SYS_PWR_REG", SDMMC_MEM_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CSSYS_MEM_SYS_PWR_REG", CSSYS_MEM_SYS_PWR_REG, 0xFFFFFFFF},
+    {"SECSS_MEM_SYS_PWR_REG", SECSS_MEM_SYS_PWR_REG, 0xFFFFFFFF},
+    {"PCIe_MEM_SYS_PWR_REG", PCIe_MEM_SYS_PWR_REG, 0xFFFFFFFF},
+    {"SATA_MEM_SYS_PWR_REG", SATA_MEM_SYS_PWR_REG, 0xFFFFFFFF},
+    {"PAD_RETENTION_DRAM_SYS_PWR_REG", PAD_RETENTION_DRAM_SYS_PWR_REG,
+            0xFFFFFFFF},
+    {"PAD_RETENTION_MAUDIO_SYS_PWR_REG", PAD_RETENTION_MAUDIO_SYS_PWR_REG,
+            0xFFFFFFFF},
+    {"PAD_RETENTION_GPIO_SYS_PWR_REG", PAD_RETENTION_GPIO_SYS_PWR_REG,
+            0xFFFFFFFF},
+    {"PAD_RETENTION_UART_SYS_PWR_REG", PAD_RETENTION_UART_SYS_PWR_REG,
+            0xFFFFFFFF},
+    {"PAD_RETENTION_MMCA_SYS_PWR_REG", PAD_RETENTION_MMCA_SYS_PWR_REG,
+            0xFFFFFFFF},
+    {"PAD_RETENTION_MMCB_SYS_PWR_REG", PAD_RETENTION_MMCB_SYS_PWR_REG,
+            0xFFFFFFFF},
+    {"PAD_RETENTION_EBIA_SYS_PWR_REG", PAD_RETENTION_EBIA_SYS_PWR_REG,
+            0xFFFFFFFF},
+    {"PAD_RETENTION_EBIB_SYS_PWR_REG", PAD_RETENTION_EBIB_SYS_PWR_REG,
+            0xFFFFFFFF},
+    {"PAD_ISOLATION_SYS_PWR_REG", PAD_ISOLATION_SYS_PWR_REG, 0xFFFFFFFF},
+    {"PAD_ALV_SEL_SYS_PWR_REG", PAD_ALV_SEL_SYS_PWR_REG, 0xFFFFFFFF},
+    {"XUSBXTI_SYS_PWR_REG", XUSBXTI_SYS_PWR_REG, 0xFFFFFFFF},
+    {"XXTI_SYS_PWR_REG", XXTI_SYS_PWR_REG, 0xFFFFFFFF},
+    {"EXT_REGULATOR_SYS_PWR_REG", EXT_REGULATOR_SYS_PWR_REG, 0xFFFFFFFF},
+    {"GPIO_MODE_SYS_PWR_REG", GPIO_MODE_SYS_PWR_REG, 0xFFFFFFFF},
+    {"GPIO_MODE_MAUDIO_SYS_PWR_REG", GPIO_MODE_MAUDIO_SYS_PWR_REG, 0xFFFFFFFF},
+    {"CAM_SYS_PWR_REG", CAM_SYS_PWR_REG, 0xFFFFFFFF},
+    {"TV_SYS_PWR_REG", TV_SYS_PWR_REG, 0xFFFFFFFF},
+    {"MFC_SYS_PWR_REG", MFC_SYS_PWR_REG, 0xFFFFFFFF},
+    {"G3D_SYS_PWR_REG", G3D_SYS_PWR_REG, 0xFFFFFFFF},
+    {"LCD0_SYS_PWR_REG", LCD0_SYS_PWR_REG, 0xFFFFFFFF},
+    {"LCD1_SYS_PWR_REG", LCD1_SYS_PWR_REG, 0xFFFFFFFF},
+    {"MAUDIO_SYS_PWR_REG", MAUDIO_SYS_PWR_REG, 0xFFFFFFFF},
+    {"GPS_SYS_PWR_REG", GPS_SYS_PWR_REG, 0xFFFFFFFF},
+    {"GPS_ALIVE_SYS_PWR_REG", GPS_ALIVE_SYS_PWR_REG, 0xFFFFFFFF},
+    {"ARM_CORE0_CONFIGURATION", ARM_CORE0_CONFIGURATION, 0x00000003},
+    {"ARM_CORE0_STATUS", ARM_CORE0_STATUS, 0x00030003},
+    {"ARM_CORE0_OPTION", ARM_CORE0_OPTION, 0x01010001},
+    {"ARM_CORE1_CONFIGURATION", ARM_CORE1_CONFIGURATION, 0x00000003},
+    {"ARM_CORE1_STATUS", ARM_CORE1_STATUS, 0x00030003},
+    {"ARM_CORE1_OPTION", ARM_CORE1_OPTION, 0x01010001},
+    {"ARM_COMMON_OPTION", ARM_COMMON_OPTION, 0x00000001},
+    {"ARM_CPU_L2_0_CONFIGURATION", ARM_CPU_L2_0_CONFIGURATION, 0x00000003},
+    {"ARM_CPU_L2_0_STATUS", ARM_CPU_L2_0_STATUS, 0x00000003},
+    {"ARM_CPU_L2_1_CONFIGURATION", ARM_CPU_L2_1_CONFIGURATION, 0x00000003},
+    {"ARM_CPU_L2_1_STATUS", ARM_CPU_L2_1_STATUS, 0x00000003},
+    {"PAD_RETENTION_MAUDIO_OPTION", PAD_RETENTION_MAUDIO_OPTION, 0x00000000},
+    {"PAD_RETENTION_GPIO_OPTION", PAD_RETENTION_GPIO_OPTION, 0x00000000},
+    {"PAD_RETENTION_UART_OPTION", PAD_RETENTION_UART_OPTION, 0x00000000},
+    {"PAD_RETENTION_MMCA_OPTION", PAD_RETENTION_MMCA_OPTION, 0x00000000},
+    {"PAD_RETENTION_MMCB_OPTION", PAD_RETENTION_MMCB_OPTION, 0x00000000},
+    {"PAD_RETENTION_EBIA_OPTION", PAD_RETENTION_EBIA_OPTION, 0x00000000},
+    {"PAD_RETENTION_EBIB_OPTION", PAD_RETENTION_EBIB_OPTION, 0x00000000},
+    {"PS_HOLD_CONTROL", PS_HOLD_CONTROL, 0x00005200},
+    {"XUSBXTI_CONFIGURATION", XUSBXTI_CONFIGURATION, 0x00000001},
+    {"XUSBXTI_STATUS", XUSBXTI_STATUS, 0x00000001},
+    {"XUSBXTI_DURATION", XUSBXTI_DURATION, 0xFFF00000},
+    {"XXTI_CONFIGURATION", XXTI_CONFIGURATION, 0x00000001},
+    {"XXTI_STATUS", XXTI_STATUS, 0x00000001},
+    {"XXTI_DURATION", XXTI_DURATION, 0xFFF00000},
+    {"EXT_REGULATOR_DURATION", EXT_REGULATOR_DURATION, 0xFFF03FFF},
+    {"CAM_CONFIGURATION", CAM_CONFIGURATION, 0x00000007},
+    {"CAM_STATUS", CAM_STATUS, 0x00060007},
+    {"CAM_OPTION", CAM_OPTION, 0x00000001},
+    {"TV_CONFIGURATION", TV_CONFIGURATION, 0x00000007},
+    {"TV_STATUS", TV_STATUS, 0x00060007},
+    {"TV_OPTION", TV_OPTION, 0x00000001},
+    {"MFC_CONFIGURATION", MFC_CONFIGURATION, 0x00000007},
+    {"MFC_STATUS", MFC_STATUS, 0x00060007},
+    {"MFC_OPTION", MFC_OPTION, 0x00000001},
+    {"G3D_CONFIGURATION", G3D_CONFIGURATION, 0x00000007},
+    {"G3D_STATUS", G3D_STATUS, 0x00060007},
+    {"G3D_OPTION", G3D_OPTION, 0x00000001},
+    {"LCD0_CONFIGURATION", LCD0_CONFIGURATION, 0x00000007},
+    {"LCD0_STATUS", LCD0_STATUS, 0x00060007},
+    {"LCD0_OPTION", LCD0_OPTION, 0x00000001},
+    {"LCD1_CONFIGURATION", LCD1_CONFIGURATION, 0x00000007},
+    {"LCD1_STATUS", LCD1_STATUS, 0x00060007},
+    {"LCD1_OPTION", LCD1_OPTION, 0x00000001},
+    {"GPS_CONFIGURATION", GPS_CONFIGURATION, 0x00000007},
+    {"GPS_STATUS", GPS_STATUS, 0x00060007},
+    {"GPS_OPTION", GPS_OPTION, 0x00000001},
+    {"GPS_ALIVE_CONFIGURATION", GPS_ALIVE_CONFIGURATION, 0x00000007},
+    {"GPS_ALIVE_STATUS", GPS_ALIVE_STATUS, 0x00060007},
+    {"GPS_ALIVE_OPTION", GPS_ALIVE_OPTION, 0x00000001},
+};
+
+#define PMU_NUM_OF_REGISTERS     \
+    (sizeof(exynos4210_pmu_regs) / sizeof(Exynos4210PmuReg))
+
+typedef struct Exynos4210PmuState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t reg[PMU_NUM_OF_REGISTERS];
+} Exynos4210PmuState;
+
+static uint64_t exynos4210_pmu_read(void *opaque, target_phys_addr_t offset,
+                                    unsigned size)
+{
+    Exynos4210PmuState *s = (Exynos4210PmuState *)opaque;
+    unsigned i;
+    const Exynos4210PmuReg *reg_p = exynos4210_pmu_regs;
+
+    for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) {
+        if (reg_p->offset == offset) {
+            PRINT_DEBUG_EXTEND("%s [0x%04x] -> 0x%04x\n", reg_p->name,
+                                   (uint32_t)offset, s->reg[i]);
+            return s->reg[i];
+        }
+        reg_p++;
+    }
+    PRINT_DEBUG("QEMU PMU ERROR: bad read offset 0x%04x\n", (uint32_t)offset);
+    return 0;
+}
+
+static void exynos4210_pmu_write(void *opaque, target_phys_addr_t offset,
+                                 uint64_t val, unsigned size)
+{
+    Exynos4210PmuState *s = (Exynos4210PmuState *)opaque;
+    unsigned i;
+    const Exynos4210PmuReg *reg_p = exynos4210_pmu_regs;
+
+    for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) {
+        if (reg_p->offset == offset) {
+            PRINT_DEBUG_EXTEND("%s <0x%04x> <- 0x%04x\n", reg_p->name,
+                    (uint32_t)offset, (uint32_t)val);
+            s->reg[i] = val;
+            return;
+        }
+        reg_p++;
+    }
+    PRINT_DEBUG("QEMU PMU ERROR: bad write offset 0x%04x\n", (uint32_t)offset);
+}
+
+static const MemoryRegionOps exynos4210_pmu_ops = {
+    .read = exynos4210_pmu_read,
+    .write = exynos4210_pmu_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false
+    }
+};
+
+static void exynos4210_pmu_reset(DeviceState *dev)
+{
+    Exynos4210PmuState *s =
+            container_of(dev, Exynos4210PmuState, busdev.qdev);
+    unsigned i;
+
+    /* Set default values for registers */
+    for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) {
+        s->reg[i] = exynos4210_pmu_regs[i].reset_value;
+    }
+}
+
+static int exynos4210_pmu_init(SysBusDevice *dev)
+{
+    Exynos4210PmuState *s = FROM_SYSBUS(Exynos4210PmuState, dev);
+
+    /* memory mapping */
+    memory_region_init_io(&s->iomem, &exynos4210_pmu_ops, s, "exynos4210.pmu",
+                          EXYNOS4210_PMU_REGS_MEM_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+    return 0;
+}
+
+static const VMStateDescription exynos4210_pmu_vmstate = {
+    .name = "exynos4210.pmu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(reg, Exynos4210PmuState, PMU_NUM_OF_REGISTERS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void exynos4210_pmu_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = exynos4210_pmu_init;
+    dc->reset = exynos4210_pmu_reset;
+    dc->vmsd = &exynos4210_pmu_vmstate;
+}
+
+static TypeInfo exynos4210_pmu_info = {
+    .name          = "exynos4210.pmu",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210PmuState),
+    .class_init    = exynos4210_pmu_class_init,
+};
+
+static void exynos4210_pmu_register(void)
+{
+    type_register_static(&exynos4210_pmu_info);
+}
+
+type_init(exynos4210_pmu_register)
commit 62db8bf39b8a0e3edb631a3d0e5bde840c780fcf
Author: Evgeny Voevodin <e.voevodin at samsung.com>
Date:   Thu Feb 16 09:56:05 2012 +0000

    ARM: exynos4210: PWM support.
    
    Signed-off-by: Evgeny Voevodin <e.voevodin at samsung.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/Makefile.target b/Makefile.target
index f501d33..bbcee06 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -345,7 +345,7 @@ obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
 obj-arm-y += versatile_pci.o
 obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
 obj-arm-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
-obj-arm-y += exynos4_boards.o exynos4210_uart.o
+obj-arm-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
 obj-arm-y += arm_l2x0.o
 obj-arm-y += arm_mptimer.o
 obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
diff --git a/hw/exynos4210.c b/hw/exynos4210.c
index 555adc0..8ebe5df 100644
--- a/hw/exynos4210.c
+++ b/hw/exynos4210.c
@@ -29,6 +29,9 @@
 
 #define EXYNOS4210_CHIPID_ADDR         0x10000000
 
+/* PWM */
+#define EXYNOS4210_PWM_BASE_ADDR       0x139D0000
+
 /* UART's definitions */
 #define EXYNOS4210_UART0_BASE_ADDR     0x13800000
 #define EXYNOS4210_UART1_BASE_ADDR     0x13810000
@@ -199,6 +202,15 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
     memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR,
             &s->dram0_mem);
 
+    /* PWM */
+    sysbus_create_varargs("exynos4210.pwm", EXYNOS4210_PWM_BASE_ADDR,
+                          s->irq_table[exynos4210_get_irq(22, 0)],
+                          s->irq_table[exynos4210_get_irq(22, 1)],
+                          s->irq_table[exynos4210_get_irq(22, 2)],
+                          s->irq_table[exynos4210_get_irq(22, 3)],
+                          s->irq_table[exynos4210_get_irq(22, 4)],
+                          NULL);
+
     /*** UARTs ***/
     exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR,
                            EXYNOS4210_UART0_FIFO_SIZE, 0, NULL,
diff --git a/hw/exynos4210_pwm.c b/hw/exynos4210_pwm.c
new file mode 100644
index 0000000..6243e59
--- /dev/null
+++ b/hw/exynos4210_pwm.c
@@ -0,0 +1,422 @@
+/*
+ * Samsung exynos4210 Pulse Width Modulation Timer
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ * All rights reserved.
+ *
+ * Evgeny Voevodin <e.voevodin at samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program 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 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 "qemu-timer.h"
+#include "qemu-common.h"
+#include "ptimer.h"
+
+#include "exynos4210.h"
+
+//#define DEBUG_PWM
+
+#ifdef DEBUG_PWM
+#define DPRINTF(fmt, ...) \
+        do { fprintf(stdout, "PWM: [%24s:%5d] " fmt, __func__, __LINE__, \
+                ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define     EXYNOS4210_PWM_TIMERS_NUM      5
+#define     EXYNOS4210_PWM_REG_MEM_SIZE    0x50
+
+#define     TCFG0        0x0000
+#define     TCFG1        0x0004
+#define     TCON         0x0008
+#define     TCNTB0       0x000C
+#define     TCMPB0       0x0010
+#define     TCNTO0       0x0014
+#define     TCNTB1       0x0018
+#define     TCMPB1       0x001C
+#define     TCNTO1       0x0020
+#define     TCNTB2       0x0024
+#define     TCMPB2       0x0028
+#define     TCNTO2       0x002C
+#define     TCNTB3       0x0030
+#define     TCMPB3       0x0034
+#define     TCNTO3       0x0038
+#define     TCNTB4       0x003C
+#define     TCNTO4       0x0040
+#define     TINT_CSTAT   0x0044
+
+#define     TCNTB(x)    (0xC * (x))
+#define     TCMPB(x)    (0xC * (x) + 1)
+#define     TCNTO(x)    (0xC * (x) + 2)
+
+#define GET_PRESCALER(reg, x) (((reg) & (0xFF << (8 * (x)))) >> 8 * (x))
+#define GET_DIVIDER(reg, x) (1 << (((reg) & (0xF << (4 * (x)))) >> (4 * (x))))
+
+/*
+ * Attention! Timer4 doesn't have OUTPUT_INVERTER,
+ * so Auto Reload bit is not accessible by macros!
+ */
+#define     TCON_TIMER_BASE(x)          (((x) ? 1 : 0) * 4 + 4 * (x))
+#define     TCON_TIMER_START(x)         (1 << (TCON_TIMER_BASE(x) + 0))
+#define     TCON_TIMER_MANUAL_UPD(x)    (1 << (TCON_TIMER_BASE(x) + 1))
+#define     TCON_TIMER_OUTPUT_INV(x)    (1 << (TCON_TIMER_BASE(x) + 2))
+#define     TCON_TIMER_AUTO_RELOAD(x)   (1 << (TCON_TIMER_BASE(x) + 3))
+#define     TCON_TIMER4_AUTO_RELOAD     (1 << 22)
+
+#define     TINT_CSTAT_STATUS(x)        (1 << (5 + (x)))
+#define     TINT_CSTAT_ENABLE(x)        (1 << (x))
+
+/* timer struct */
+typedef struct {
+    uint32_t    id;             /* timer id */
+    qemu_irq    irq;            /* local timer irq */
+    uint32_t    freq;           /* timer frequency */
+
+    /* use ptimer.c to represent count down timer */
+    ptimer_state *ptimer;       /* timer  */
+
+    /* registers */
+    uint32_t    reg_tcntb;      /* counter register buffer */
+    uint32_t    reg_tcmpb;      /* compare register buffer */
+
+    struct Exynos4210PWMState *parent;
+
+} Exynos4210PWM;
+
+
+typedef struct Exynos4210PWMState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    uint32_t    reg_tcfg[2];
+    uint32_t    reg_tcon;
+    uint32_t    reg_tint_cstat;
+
+    Exynos4210PWM timer[EXYNOS4210_PWM_TIMERS_NUM];
+
+} Exynos4210PWMState;
+
+/*** VMState ***/
+static const VMStateDescription vmstate_exynos4210_pwm = {
+    .name = "exynos4210.pwm.pwm",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(id, Exynos4210PWM),
+        VMSTATE_UINT32(freq, Exynos4210PWM),
+        VMSTATE_PTIMER(ptimer, Exynos4210PWM),
+        VMSTATE_UINT32(reg_tcntb, Exynos4210PWM),
+        VMSTATE_UINT32(reg_tcmpb, Exynos4210PWM),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_exynos4210_pwm_state = {
+    .name = "exynos4210.pwm",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(reg_tcfg, Exynos4210PWMState, 2),
+        VMSTATE_UINT32(reg_tcon, Exynos4210PWMState),
+        VMSTATE_UINT32(reg_tint_cstat, Exynos4210PWMState),
+        VMSTATE_STRUCT_ARRAY(timer, Exynos4210PWMState,
+            EXYNOS4210_PWM_TIMERS_NUM, 0,
+        vmstate_exynos4210_pwm, Exynos4210PWM),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/*
+ * PWM update frequency
+ */
+static void exynos4210_pwm_update_freq(Exynos4210PWMState *s, uint32_t id)
+{
+    uint32_t freq;
+    freq = s->timer[id].freq;
+    if (id > 1) {
+        s->timer[id].freq = 24000000 /
+        ((GET_PRESCALER(s->reg_tcfg[0], 1) + 1) *
+                (GET_DIVIDER(s->reg_tcfg[1], id)));
+    } else {
+        s->timer[id].freq = 24000000 /
+        ((GET_PRESCALER(s->reg_tcfg[0], 0) + 1) *
+                (GET_DIVIDER(s->reg_tcfg[1], id)));
+    }
+
+    if (freq != s->timer[id].freq) {
+        ptimer_set_freq(s->timer[id].ptimer, s->timer[id].freq);
+        DPRINTF("freq=%dHz\n", s->timer[id].freq);
+    }
+}
+
+/*
+ * Counter tick handler
+ */
+static void exynos4210_pwm_tick(void *opaque)
+{
+    Exynos4210PWM *s = (Exynos4210PWM *)opaque;
+    Exynos4210PWMState *p = (Exynos4210PWMState *)s->parent;
+    uint32_t id = s->id;
+    bool cmp;
+
+    DPRINTF("timer %d tick\n", id);
+
+    /* set irq status */
+    p->reg_tint_cstat |= TINT_CSTAT_STATUS(id);
+
+    /* raise IRQ */
+    if (p->reg_tint_cstat & TINT_CSTAT_ENABLE(id)) {
+        DPRINTF("timer %d IRQ\n", id);
+        qemu_irq_raise(p->timer[id].irq);
+    }
+
+    /* reload timer */
+    if (id != 4) {
+        cmp = p->reg_tcon & TCON_TIMER_AUTO_RELOAD(id);
+    } else {
+        cmp = p->reg_tcon & TCON_TIMER4_AUTO_RELOAD;
+    }
+
+    if (cmp) {
+        DPRINTF("auto reload timer %d count to %x\n", id,
+                p->timer[id].reg_tcntb);
+        ptimer_set_count(p->timer[id].ptimer, p->timer[id].reg_tcntb);
+        ptimer_run(p->timer[id].ptimer, 1);
+    } else {
+        /* stop timer, set status to STOP, see Basic Timer Operation */
+        p->reg_tcon = ~TCON_TIMER_START(id);
+        ptimer_stop(p->timer[id].ptimer);
+    }
+}
+
+/*
+ * PWM Read
+ */
+static uint64_t exynos4210_pwm_read(void *opaque, target_phys_addr_t offset,
+        unsigned size)
+{
+    Exynos4210PWMState *s = (Exynos4210PWMState *)opaque;
+    uint32_t value = 0;
+    int index;
+
+    switch (offset) {
+    case TCFG0: case TCFG1:
+        index = (offset - TCFG0) >> 2;
+        value = s->reg_tcfg[index];
+        break;
+
+    case TCON:
+        value = s->reg_tcon;
+        break;
+
+    case TCNTB0: case TCNTB1:
+    case TCNTB2: case TCNTB3: case TCNTB4:
+        index = (offset - TCNTB0) / 0xC;
+        value = s->timer[index].reg_tcntb;
+        break;
+
+    case TCMPB0: case TCMPB1:
+    case TCMPB2: case TCMPB3:
+        index = (offset - TCMPB0) / 0xC;
+        value = s->timer[index].reg_tcmpb;
+        break;
+
+    case TCNTO0: case TCNTO1:
+    case TCNTO2: case TCNTO3: case TCNTO4:
+        index = (offset == TCNTO4) ? 4 : (offset - TCNTO0) / 0xC;
+        value = ptimer_get_count(s->timer[index].ptimer);
+        break;
+
+    case TINT_CSTAT:
+        value = s->reg_tint_cstat;
+        break;
+
+    default:
+        fprintf(stderr,
+                "[exynos4210.pwm: bad read offset " TARGET_FMT_plx "]\n",
+                offset);
+        break;
+    }
+    return value;
+}
+
+/*
+ * PWM Write
+ */
+static void exynos4210_pwm_write(void *opaque, target_phys_addr_t offset,
+        uint64_t value, unsigned size)
+{
+    Exynos4210PWMState *s = (Exynos4210PWMState *)opaque;
+    int index;
+    uint32_t new_val;
+    int i;
+
+    switch (offset) {
+    case TCFG0: case TCFG1:
+        index = (offset - TCFG0) >> 2;
+        s->reg_tcfg[index] = value;
+
+        /* update timers frequencies */
+        for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
+            exynos4210_pwm_update_freq(s, s->timer[i].id);
+        }
+        break;
+
+    case TCON:
+        for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
+            if ((value & TCON_TIMER_MANUAL_UPD(i)) >
+            (s->reg_tcon & TCON_TIMER_MANUAL_UPD(i))) {
+                /*
+                 * TCNTB and TCMPB are loaded into TCNT and TCMP.
+                 * Update timers.
+                 */
+
+                /* this will start timer to run, this ok, because
+                 * during processing start bit timer will be stopped
+                 * if needed */
+                ptimer_set_count(s->timer[i].ptimer, s->timer[i].reg_tcntb);
+                DPRINTF("set timer %d count to %x\n", i,
+                        s->timer[i].reg_tcntb);
+            }
+
+            if ((value & TCON_TIMER_START(i)) >
+            (s->reg_tcon & TCON_TIMER_START(i))) {
+                /* changed to start */
+                ptimer_run(s->timer[i].ptimer, 1);
+                DPRINTF("run timer %d\n", i);
+            }
+
+            if ((value & TCON_TIMER_START(i)) <
+                    (s->reg_tcon & TCON_TIMER_START(i))) {
+                /* changed to stop */
+                ptimer_stop(s->timer[i].ptimer);
+                DPRINTF("stop timer %d\n", i);
+            }
+        }
+        s->reg_tcon = value;
+        break;
+
+    case TCNTB0: case TCNTB1:
+    case TCNTB2: case TCNTB3: case TCNTB4:
+        index = (offset - TCNTB0) / 0xC;
+        s->timer[index].reg_tcntb = value;
+        break;
+
+    case TCMPB0: case TCMPB1:
+    case TCMPB2: case TCMPB3:
+        index = (offset - TCMPB0) / 0xC;
+        s->timer[index].reg_tcmpb = value;
+        break;
+
+    case TINT_CSTAT:
+        new_val = (s->reg_tint_cstat & 0x3E0) + (0x1F & value);
+        new_val &= ~(0x3E0 & value);
+
+        for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
+            if ((new_val & TINT_CSTAT_STATUS(i)) <
+                    (s->reg_tint_cstat & TINT_CSTAT_STATUS(i))) {
+                qemu_irq_lower(s->timer[i].irq);
+            }
+        }
+
+        s->reg_tint_cstat = new_val;
+        break;
+
+    default:
+        fprintf(stderr,
+                "[exynos4210.pwm: bad write offset " TARGET_FMT_plx "]\n",
+                offset);
+        break;
+
+    }
+}
+
+/*
+ * Set default values to timer fields and registers
+ */
+static void exynos4210_pwm_reset(DeviceState *d)
+{
+    Exynos4210PWMState *s = (Exynos4210PWMState *)d;
+    int i;
+    s->reg_tcfg[0] = 0x0101;
+    s->reg_tcfg[1] = 0x0;
+    s->reg_tcon = 0;
+    s->reg_tint_cstat = 0;
+    for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
+        s->timer[i].reg_tcmpb = 0;
+        s->timer[i].reg_tcntb = 0;
+
+        exynos4210_pwm_update_freq(s, s->timer[i].id);
+        ptimer_stop(s->timer[i].ptimer);
+    }
+}
+
+static const MemoryRegionOps exynos4210_pwm_ops = {
+    .read = exynos4210_pwm_read,
+    .write = exynos4210_pwm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/*
+ * PWM timer initialization
+ */
+static int exynos4210_pwm_init(SysBusDevice *dev)
+{
+    Exynos4210PWMState *s = FROM_SYSBUS(Exynos4210PWMState, dev);
+    int i;
+    QEMUBH *bh;
+
+    for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) {
+        bh = qemu_bh_new(exynos4210_pwm_tick, &s->timer[i]);
+        sysbus_init_irq(dev, &s->timer[i].irq);
+        s->timer[i].ptimer = ptimer_init(bh);
+        s->timer[i].id = i;
+        s->timer[i].parent = s;
+    }
+
+    memory_region_init_io(&s->iomem, &exynos4210_pwm_ops, s, "exynos4210-pwm",
+            EXYNOS4210_PWM_REG_MEM_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void exynos4210_pwm_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = exynos4210_pwm_init;
+    dc->reset = exynos4210_pwm_reset;
+    dc->vmsd = &vmstate_exynos4210_pwm_state;
+}
+
+static TypeInfo exynos4210_pwm_info = {
+    .name          = "exynos4210.pwm",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210PWMState),
+    .class_init    = exynos4210_pwm_class_init,
+};
+
+static void exynos4210_pwm_register_types(void)
+{
+    type_register_static(&exynos4210_pwm_info);
+}
+
+type_init(exynos4210_pwm_register_types)
commit e5a4914efc75c8880d7088dc0871766e5b73673f
Author: Maksim Kozlov <m.kozlov at samsung.com>
Date:   Thu Feb 16 09:56:05 2012 +0000

    ARM: exynos4210: UART support
    
    Add basic support of exynos4210 UART
    
    Signed-off-by: Maksim Kozlov <m.kozlov at samsung.com>
    Signed-off-by: Evgeny Voevodin <e.voevodin at samsung.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/Makefile.target b/Makefile.target
index c9afbd3..f501d33 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -345,7 +345,7 @@ obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
 obj-arm-y += versatile_pci.o
 obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
 obj-arm-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
-obj-arm-y += exynos4_boards.o
+obj-arm-y += exynos4_boards.o exynos4210_uart.o
 obj-arm-y += arm_l2x0.o
 obj-arm-y += arm_mptimer.o
 obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
diff --git a/hw/exynos4210.c b/hw/exynos4210.c
index 5b1e24c..555adc0 100644
--- a/hw/exynos4210.c
+++ b/hw/exynos4210.c
@@ -29,6 +29,18 @@
 
 #define EXYNOS4210_CHIPID_ADDR         0x10000000
 
+/* UART's definitions */
+#define EXYNOS4210_UART0_BASE_ADDR     0x13800000
+#define EXYNOS4210_UART1_BASE_ADDR     0x13810000
+#define EXYNOS4210_UART2_BASE_ADDR     0x13820000
+#define EXYNOS4210_UART3_BASE_ADDR     0x13830000
+#define EXYNOS4210_UART0_FIFO_SIZE     256
+#define EXYNOS4210_UART1_FIFO_SIZE     64
+#define EXYNOS4210_UART2_FIFO_SIZE     16
+#define EXYNOS4210_UART3_FIFO_SIZE     16
+/* Interrupt Group of External Interrupt Combiner for UART */
+#define EXYNOS4210_UART_INT_GRP        26
+
 /* External GIC */
 #define EXYNOS4210_EXT_GIC_CPU_BASE_ADDR    0x10480000
 #define EXYNOS4210_EXT_GIC_DIST_BASE_ADDR   0x10490000
@@ -187,5 +199,22 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
     memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR,
             &s->dram0_mem);
 
+    /*** UARTs ***/
+    exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR,
+                           EXYNOS4210_UART0_FIFO_SIZE, 0, NULL,
+                  s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]);
+
+    exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR,
+                           EXYNOS4210_UART1_FIFO_SIZE, 1, NULL,
+                  s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]);
+
+    exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR,
+                           EXYNOS4210_UART2_FIFO_SIZE, 2, NULL,
+                  s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]);
+
+    exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR,
+                           EXYNOS4210_UART3_FIFO_SIZE, 3, NULL,
+                  s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]);
+
     return s;
 }
diff --git a/hw/exynos4210.h b/hw/exynos4210.h
index 0026a52..e7522f8 100644
--- a/hw/exynos4210.h
+++ b/hw/exynos4210.h
@@ -119,4 +119,13 @@ uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit);
 void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev,
         int ext);
 
+/*
+ * exynos4210 UART
+ */
+DeviceState *exynos4210_uart_create(target_phys_addr_t addr,
+                                    int fifo_size,
+                                    int channel,
+                                    CharDriverState *chr,
+                                    qemu_irq irq);
+
 #endif /* EXYNOS4210_H_ */
diff --git a/hw/exynos4210_uart.c b/hw/exynos4210_uart.c
new file mode 100644
index 0000000..73a9c18
--- /dev/null
+++ b/hw/exynos4210_uart.c
@@ -0,0 +1,676 @@
+/*
+ *  Exynos4210 UART Emulation
+ *
+ *  Copyright (C) 2011 Samsung Electronics Co Ltd.
+ *    Maksim Kozlov, <m.kozlov at samsung.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 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 "sysemu.h"
+#include "qemu-char.h"
+
+#include "exynos4210.h"
+
+#undef DEBUG_UART
+#undef DEBUG_UART_EXTEND
+#undef DEBUG_IRQ
+#undef DEBUG_Rx_DATA
+#undef DEBUG_Tx_DATA
+
+#define DEBUG_UART            0
+#define DEBUG_UART_EXTEND     0
+#define DEBUG_IRQ             0
+#define DEBUG_Rx_DATA         0
+#define DEBUG_Tx_DATA         0
+
+#if DEBUG_UART
+#define  PRINT_DEBUG(fmt, args...)  \
+        do { \
+            fprintf(stderr, "  [%s:%d]   "fmt, __func__, __LINE__, ##args); \
+        } while (0)
+
+#if DEBUG_UART_EXTEND
+#define  PRINT_DEBUG_EXTEND(fmt, args...) \
+        do { \
+            fprintf(stderr, "  [%s:%d]   "fmt, __func__, __LINE__, ##args); \
+        } while (0)
+#else
+#define  PRINT_DEBUG_EXTEND(fmt, args...) \
+        do {} while (0)
+#endif /* EXTEND */
+
+#else
+#define  PRINT_DEBUG(fmt, args...)  \
+        do {} while (0)
+#define  PRINT_DEBUG_EXTEND(fmt, args...) \
+        do {} while (0)
+#endif
+
+#define  PRINT_ERROR(fmt, args...) \
+        do { \
+            fprintf(stderr, "  [%s:%d]   "fmt, __func__, __LINE__, ##args); \
+        } while (0)
+
+/*
+ *  Offsets for UART registers relative to SFR base address
+ *  for UARTn
+ *
+ */
+#define ULCON      0x0000 /* Line Control             */
+#define UCON       0x0004 /* Control                  */
+#define UFCON      0x0008 /* FIFO Control             */
+#define UMCON      0x000C /* Modem Control            */
+#define UTRSTAT    0x0010 /* Tx/Rx Status             */
+#define UERSTAT    0x0014 /* UART Error Status        */
+#define UFSTAT     0x0018 /* FIFO Status              */
+#define UMSTAT     0x001C /* Modem Status             */
+#define UTXH       0x0020 /* Transmit Buffer          */
+#define URXH       0x0024 /* Receive Buffer           */
+#define UBRDIV     0x0028 /* Baud Rate Divisor        */
+#define UFRACVAL   0x002C /* Divisor Fractional Value */
+#define UINTP      0x0030 /* Interrupt Pending        */
+#define UINTSP     0x0034 /* Interrupt Source Pending */
+#define UINTM      0x0038 /* Interrupt Mask           */
+
+/*
+ * for indexing register in the uint32_t array
+ *
+ * 'reg' - register offset (see offsets definitions above)
+ *
+ */
+#define I_(reg) (reg / sizeof(uint32_t))
+
+typedef struct Exynos4210UartReg {
+    const char         *name; /* the only reason is the debug output */
+    target_phys_addr_t  offset;
+    uint32_t            reset_value;
+} Exynos4210UartReg;
+
+static Exynos4210UartReg exynos4210_uart_regs[] = {
+    {"ULCON",    ULCON,    0x00000000},
+    {"UCON",     UCON,     0x00003000},
+    {"UFCON",    UFCON,    0x00000000},
+    {"UMCON",    UMCON,    0x00000000},
+    {"UTRSTAT",  UTRSTAT,  0x00000006}, /* RO */
+    {"UERSTAT",  UERSTAT,  0x00000000}, /* RO */
+    {"UFSTAT",   UFSTAT,   0x00000000}, /* RO */
+    {"UMSTAT",   UMSTAT,   0x00000000}, /* RO */
+    {"UTXH",     UTXH,     0x5c5c5c5c}, /* WO, undefined reset value*/
+    {"URXH",     URXH,     0x00000000}, /* RO */
+    {"UBRDIV",   UBRDIV,   0x00000000},
+    {"UFRACVAL", UFRACVAL, 0x00000000},
+    {"UINTP",    UINTP,    0x00000000},
+    {"UINTSP",   UINTSP,   0x00000000},
+    {"UINTM",    UINTM,    0x00000000},
+};
+
+#define EXYNOS4210_UART_REGS_MEM_SIZE    0x3C
+
+/* UART FIFO Control */
+#define UFCON_FIFO_ENABLE                    0x1
+#define UFCON_Rx_FIFO_RESET                  0x2
+#define UFCON_Tx_FIFO_RESET                  0x4
+#define UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT    8
+#define UFCON_Tx_FIFO_TRIGGER_LEVEL (7 << UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT)
+#define UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT    4
+#define UFCON_Rx_FIFO_TRIGGER_LEVEL (7 << UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT)
+
+/* Uart FIFO Status */
+#define UFSTAT_Rx_FIFO_COUNT        0xff
+#define UFSTAT_Rx_FIFO_FULL         0x100
+#define UFSTAT_Rx_FIFO_ERROR        0x200
+#define UFSTAT_Tx_FIFO_COUNT_SHIFT  16
+#define UFSTAT_Tx_FIFO_COUNT        (0xff << UFSTAT_Tx_FIFO_COUNT_SHIFT)
+#define UFSTAT_Tx_FIFO_FULL_SHIFT   24
+#define UFSTAT_Tx_FIFO_FULL         (1 << UFSTAT_Tx_FIFO_FULL_SHIFT)
+
+/* UART Interrupt Source Pending */
+#define UINTSP_RXD      0x1 /* Receive interrupt  */
+#define UINTSP_ERROR    0x2 /* Error interrupt    */
+#define UINTSP_TXD      0x4 /* Transmit interrupt */
+#define UINTSP_MODEM    0x8 /* Modem interrupt    */
+
+/* UART Line Control */
+#define ULCON_IR_MODE_SHIFT   6
+#define ULCON_PARITY_SHIFT    3
+#define ULCON_STOP_BIT_SHIFT  1
+
+/* UART Tx/Rx Status */
+#define UTRSTAT_TRANSMITTER_EMPTY       0x4
+#define UTRSTAT_Tx_BUFFER_EMPTY         0x2
+#define UTRSTAT_Rx_BUFFER_DATA_READY    0x1
+
+/* UART Error Status */
+#define UERSTAT_OVERRUN  0x1
+#define UERSTAT_PARITY   0x2
+#define UERSTAT_FRAME    0x4
+#define UERSTAT_BREAK    0x8
+
+typedef struct {
+    uint8_t    *data;
+    uint32_t    sp, rp; /* store and retrieve pointers */
+    uint32_t    size;
+} Exynos4210UartFIFO;
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    uint32_t             reg[EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)];
+    Exynos4210UartFIFO   rx;
+    Exynos4210UartFIFO   tx;
+
+    CharDriverState  *chr;
+    qemu_irq          irq;
+
+    uint32_t channel;
+
+} Exynos4210UartState;
+
+
+#if DEBUG_UART
+/* Used only for debugging inside PRINT_DEBUG_... macros */
+static const char *exynos4210_uart_regname(target_phys_addr_t  offset)
+{
+
+    int regs_number = sizeof(exynos4210_uart_regs) / sizeof(Exynos4210UartReg);
+    int i;
+
+    for (i = 0; i < regs_number; i++) {
+        if (offset == exynos4210_uart_regs[i].offset) {
+            return exynos4210_uart_regs[i].name;
+        }
+    }
+
+    return NULL;
+}
+#endif
+
+
+static void fifo_store(Exynos4210UartFIFO *q, uint8_t ch)
+{
+    q->data[q->sp] = ch;
+    q->sp = (q->sp + 1) % q->size;
+}
+
+static uint8_t fifo_retrieve(Exynos4210UartFIFO *q)
+{
+    uint8_t ret = q->data[q->rp];
+    q->rp = (q->rp + 1) % q->size;
+    return  ret;
+}
+
+static int fifo_elements_number(Exynos4210UartFIFO *q)
+{
+    if (q->sp < q->rp) {
+        return q->size - q->rp + q->sp;
+    }
+
+    return q->sp - q->rp;
+}
+
+static int fifo_empty_elements_number(Exynos4210UartFIFO *q)
+{
+    return q->size - fifo_elements_number(q);
+}
+
+static void fifo_reset(Exynos4210UartFIFO *q)
+{
+    if (q->data != NULL) {
+        g_free(q->data);
+        q->data = NULL;
+    }
+
+    q->data = (uint8_t *)g_malloc0(q->size);
+
+    q->sp = 0;
+    q->rp = 0;
+}
+
+static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(Exynos4210UartState *s)
+{
+    uint32_t level = 0;
+    uint32_t reg;
+
+    reg = (s->reg[I_(UFCON)] && UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
+            UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT;
+
+    switch (s->channel) {
+    case 0:
+        level = reg * 32;
+        break;
+    case 1:
+    case 4:
+        level = reg * 8;
+        break;
+    case 2:
+    case 3:
+        level = reg * 2;
+        break;
+    default:
+        level = 0;
+        PRINT_ERROR("Wrong UART channel number: %d\n", s->channel);
+    }
+
+    return level;
+}
+
+static void exynos4210_uart_update_irq(Exynos4210UartState *s)
+{
+    /*
+     * The Tx interrupt is always requested if the number of data in the
+     * transmit FIFO is smaller than the trigger level.
+     */
+    if (s->reg[I_(UFCON)] && UFCON_FIFO_ENABLE) {
+
+        uint32_t count = (s->reg[I_(UFSTAT)] && UFSTAT_Tx_FIFO_COUNT) >>
+                UFSTAT_Tx_FIFO_COUNT_SHIFT;
+
+        if (count <= exynos4210_uart_Tx_FIFO_trigger_level(s)) {
+            s->reg[I_(UINTSP)] |= UINTSP_TXD;
+        }
+    }
+
+    s->reg[I_(UINTP)] = s->reg[I_(UINTSP)] & ~s->reg[I_(UINTM)];
+
+    if (s->reg[I_(UINTP)]) {
+        qemu_irq_raise(s->irq);
+
+#if DEBUG_IRQ
+        fprintf(stderr, "UART%d: IRQ has been raised: %08x\n",
+                s->channel, s->reg[I_(UINTP)]);
+#endif
+
+    } else {
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
+{
+    int speed, parity, data_bits, stop_bits, frame_size;
+    QEMUSerialSetParams ssp;
+    uint64_t uclk_rate;
+
+    if (s->reg[I_(UBRDIV)] == 0) {
+        return;
+    }
+
+    frame_size = 1; /* start bit */
+    if (s->reg[I_(ULCON)] & 0x20) {
+        frame_size++; /* parity bit */
+        if (s->reg[I_(ULCON)] & 0x28) {
+            parity = 'E';
+        } else {
+            parity = 'O';
+        }
+    } else {
+        parity = 'N';
+    }
+
+    if (s->reg[I_(ULCON)] & 0x4) {
+        stop_bits = 2;
+    } else {
+        stop_bits = 1;
+    }
+
+    data_bits = (s->reg[I_(ULCON)] & 0x3) + 5;
+
+    frame_size += data_bits + stop_bits;
+
+    uclk_rate = 24000000;
+
+    speed = uclk_rate / ((16 * (s->reg[I_(UBRDIV)]) & 0xffff) +
+            (s->reg[I_(UFRACVAL)] & 0x7) + 16);
+
+    ssp.speed     = speed;
+    ssp.parity    = parity;
+    ssp.data_bits = data_bits;
+    ssp.stop_bits = stop_bits;
+
+    qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+
+    PRINT_DEBUG("UART%d: speed: %d, parity: %c, data: %d, stop: %d\n",
+                s->channel, speed, parity, data_bits, stop_bits);
+}
+
+static void exynos4210_uart_write(void *opaque, target_phys_addr_t offset,
+                               uint64_t val, unsigned size)
+{
+    Exynos4210UartState *s = (Exynos4210UartState *)opaque;
+    uint8_t ch;
+
+    PRINT_DEBUG_EXTEND("UART%d: <0x%04x> %s <- 0x%08llx\n", s->channel,
+        offset, exynos4210_uart_regname(offset), (long long unsigned int)val);
+
+    switch (offset) {
+    case ULCON:
+    case UBRDIV:
+    case UFRACVAL:
+        s->reg[I_(offset)] = val;
+        exynos4210_uart_update_parameters(s);
+        break;
+    case UFCON:
+        s->reg[I_(UFCON)] = val;
+        if (val & UFCON_Rx_FIFO_RESET) {
+            fifo_reset(&s->rx);
+            s->reg[I_(UFCON)] &= ~UFCON_Rx_FIFO_RESET;
+            PRINT_DEBUG("UART%d: Rx FIFO Reset\n", s->channel);
+        }
+        if (val & UFCON_Tx_FIFO_RESET) {
+            fifo_reset(&s->tx);
+            s->reg[I_(UFCON)] &= ~UFCON_Tx_FIFO_RESET;
+            PRINT_DEBUG("UART%d: Tx FIFO Reset\n", s->channel);
+        }
+        break;
+
+    case UTXH:
+        if (s->chr) {
+            s->reg[I_(UTRSTAT)] &= ~(UTRSTAT_TRANSMITTER_EMPTY |
+                    UTRSTAT_Tx_BUFFER_EMPTY);
+            ch = (uint8_t)val;
+            qemu_chr_fe_write(s->chr, &ch, 1);
+#if DEBUG_Tx_DATA
+            fprintf(stderr, "%c", ch);
+#endif
+            s->reg[I_(UTRSTAT)] |= UTRSTAT_TRANSMITTER_EMPTY |
+                    UTRSTAT_Tx_BUFFER_EMPTY;
+            s->reg[I_(UINTSP)]  |= UINTSP_TXD;
+            exynos4210_uart_update_irq(s);
+        }
+        break;
+
+    case UINTP:
+        s->reg[I_(UINTP)] &= ~val;
+        s->reg[I_(UINTSP)] &= ~val;
+        PRINT_DEBUG("UART%d: UINTP [%04x] have been cleared: %08x\n",
+                    s->channel, offset, s->reg[I_(UINTP)]);
+        exynos4210_uart_update_irq(s);
+        break;
+    case UTRSTAT:
+    case UERSTAT:
+    case UFSTAT:
+    case UMSTAT:
+    case URXH:
+        PRINT_DEBUG("UART%d: Trying to write into RO register: %s [%04x]\n",
+                    s->channel, exynos4210_uart_regname(offset), offset);
+        break;
+    case UINTSP:
+        s->reg[I_(UINTSP)]  &= ~val;
+        break;
+    case UINTM:
+        s->reg[I_(UINTM)] = val;
+        exynos4210_uart_update_irq(s);
+        break;
+    case UCON:
+    case UMCON:
+    default:
+        s->reg[I_(offset)] = val;
+        break;
+    }
+}
+static uint64_t exynos4210_uart_read(void *opaque, target_phys_addr_t offset,
+                                  unsigned size)
+{
+    Exynos4210UartState *s = (Exynos4210UartState *)opaque;
+    uint32_t res;
+
+    switch (offset) {
+    case UERSTAT: /* Read Only */
+        res = s->reg[I_(UERSTAT)];
+        s->reg[I_(UERSTAT)] = 0;
+        return res;
+    case UFSTAT: /* Read Only */
+        s->reg[I_(UFSTAT)] = fifo_elements_number(&s->rx) & 0xff;
+        if (fifo_empty_elements_number(&s->rx) == 0) {
+            s->reg[I_(UFSTAT)] |= UFSTAT_Rx_FIFO_FULL;
+            s->reg[I_(UFSTAT)] &= ~0xff;
+        }
+        return s->reg[I_(UFSTAT)];
+    case URXH:
+        if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
+            if (fifo_elements_number(&s->rx)) {
+                res = fifo_retrieve(&s->rx);
+#if DEBUG_Rx_DATA
+                fprintf(stderr, "%c", res);
+#endif
+                if (!fifo_elements_number(&s->rx)) {
+                    s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
+                } else {
+                    s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
+                }
+            } else {
+                s->reg[I_(UINTSP)] |= UINTSP_ERROR;
+                exynos4210_uart_update_irq(s);
+                res = 0;
+            }
+        } else {
+            s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
+            res = s->reg[I_(URXH)];
+        }
+        return res;
+    case UTXH:
+        PRINT_DEBUG("UART%d: Trying to read from WO register: %s [%04x]\n",
+                    s->channel, exynos4210_uart_regname(offset), offset);
+        break;
+    default:
+        return s->reg[I_(offset)];
+    }
+
+    return 0;
+}
+
+static const MemoryRegionOps exynos4210_uart_ops = {
+    .read = exynos4210_uart_read,
+    .write = exynos4210_uart_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .max_access_size = 4,
+        .unaligned = false
+    },
+};
+
+static int exynos4210_uart_can_receive(void *opaque)
+{
+    Exynos4210UartState *s = (Exynos4210UartState *)opaque;
+
+    return fifo_empty_elements_number(&s->rx);
+}
+
+
+static void exynos4210_uart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    Exynos4210UartState *s = (Exynos4210UartState *)opaque;
+    int i;
+
+    if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
+        if (fifo_empty_elements_number(&s->rx) < size) {
+            for (i = 0; i < fifo_empty_elements_number(&s->rx); i++) {
+                fifo_store(&s->rx, buf[i]);
+            }
+            s->reg[I_(UINTSP)] |= UINTSP_ERROR;
+            s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
+        } else {
+            for (i = 0; i < size; i++) {
+                fifo_store(&s->rx, buf[i]);
+            }
+            s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
+        }
+        /* XXX: Around here we maybe should check Rx trigger level */
+        s->reg[I_(UINTSP)] |= UINTSP_RXD;
+    } else {
+        s->reg[I_(URXH)] = buf[0];
+        s->reg[I_(UINTSP)] |= UINTSP_RXD;
+        s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
+    }
+
+    exynos4210_uart_update_irq(s);
+}
+
+
+static void exynos4210_uart_event(void *opaque, int event)
+{
+    Exynos4210UartState *s = (Exynos4210UartState *)opaque;
+
+    if (event == CHR_EVENT_BREAK) {
+        /* When the RxDn is held in logic 0, then a null byte is pushed into the
+         * fifo */
+        fifo_store(&s->rx, '\0');
+        s->reg[I_(UERSTAT)] |= UERSTAT_BREAK;
+        exynos4210_uart_update_irq(s);
+    }
+}
+
+
+static void exynos4210_uart_reset(DeviceState *dev)
+{
+    Exynos4210UartState *s =
+            container_of(dev, Exynos4210UartState, busdev.qdev);
+    int regs_number = sizeof(exynos4210_uart_regs)/sizeof(Exynos4210UartReg);
+    int i;
+
+    for (i = 0; i < regs_number; i++) {
+        s->reg[I_(exynos4210_uart_regs[i].offset)] =
+                exynos4210_uart_regs[i].reset_value;
+    }
+
+    fifo_reset(&s->rx);
+    fifo_reset(&s->tx);
+
+    PRINT_DEBUG("UART%d: Rx FIFO size: %d\n", s->channel, s->rx.size);
+}
+
+static const VMStateDescription vmstate_exynos4210_uart_fifo = {
+    .name = "exynos4210.uart.fifo",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(sp, Exynos4210UartFIFO),
+        VMSTATE_UINT32(rp, Exynos4210UartFIFO),
+        VMSTATE_VBUFFER_UINT32(data, Exynos4210UartFIFO, 1, NULL, 0, size),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_exynos4210_uart = {
+    .name = "exynos4210.uart",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(rx, Exynos4210UartState, 1,
+                       vmstate_exynos4210_uart_fifo, Exynos4210UartFIFO),
+        VMSTATE_UINT32_ARRAY(reg, Exynos4210UartState,
+                             EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+DeviceState *exynos4210_uart_create(target_phys_addr_t addr,
+                                 int fifo_size,
+                                 int channel,
+                                 CharDriverState *chr,
+                                 qemu_irq irq)
+{
+    DeviceState  *dev;
+    SysBusDevice *bus;
+
+    const char chr_name[] = "serial";
+    char label[ARRAY_SIZE(chr_name) + 1];
+
+    dev = qdev_create(NULL, "exynos4210.uart");
+
+    if (!chr) {
+        if (channel >= MAX_SERIAL_PORTS) {
+            hw_error("Only %d serial ports are supported by QEMU.\n",
+                     MAX_SERIAL_PORTS);
+        }
+        chr = serial_hds[channel];
+        if (!chr) {
+            snprintf(label, ARRAY_SIZE(label), "%s%d", chr_name, channel);
+            chr = qemu_chr_new(label, "null", NULL);
+            if (!(chr)) {
+                hw_error("Can't assign serial port to UART%d.\n", channel);
+            }
+        }
+    }
+
+    qdev_prop_set_chr(dev, "chardev", chr);
+    qdev_prop_set_uint32(dev, "channel", channel);
+    qdev_prop_set_uint32(dev, "rx-size", fifo_size);
+    qdev_prop_set_uint32(dev, "tx-size", fifo_size);
+
+    bus = sysbus_from_qdev(dev);
+    qdev_init_nofail(dev);
+    if (addr != (target_phys_addr_t)-1) {
+        sysbus_mmio_map(bus, 0, addr);
+    }
+    sysbus_connect_irq(bus, 0, irq);
+
+    return dev;
+}
+
+static int exynos4210_uart_init(SysBusDevice *dev)
+{
+    Exynos4210UartState *s = FROM_SYSBUS(Exynos4210UartState, dev);
+
+    /* memory mapping */
+    memory_region_init_io(&s->iomem, &exynos4210_uart_ops, s, "exynos4210.uart",
+                          EXYNOS4210_UART_REGS_MEM_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    qemu_chr_add_handlers(s->chr, exynos4210_uart_can_receive,
+                          exynos4210_uart_receive, exynos4210_uart_event, s);
+
+    return 0;
+}
+
+static Property exynos4210_uart_properties[] = {
+    DEFINE_PROP_CHR("chardev", Exynos4210UartState, chr),
+    DEFINE_PROP_UINT32("channel", Exynos4210UartState, channel, 0),
+    DEFINE_PROP_UINT32("rx-size", Exynos4210UartState, rx.size, 16),
+    DEFINE_PROP_UINT32("tx-size", Exynos4210UartState, tx.size, 16),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void exynos4210_uart_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = exynos4210_uart_init;
+    dc->reset = exynos4210_uart_reset;
+    dc->props = exynos4210_uart_properties;
+    dc->vmsd = &vmstate_exynos4210_uart;
+}
+
+static TypeInfo exynos4210_uart_info = {
+    .name          = "exynos4210.uart",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210UartState),
+    .class_init    = exynos4210_uart_class_init,
+};
+
+static void exynos4210_uart_register(void)
+{
+    type_register_static(&exynos4210_uart_info);
+}
+
+type_init(exynos4210_uart_register)
commit 0caa711335a676225041d014d49e65992f9f269f
Author: Evgeny Voevodin <e.voevodin at samsung.com>
Date:   Thu Feb 16 09:56:05 2012 +0000

    ARM: Samsung exynos4210-based boards emulation
    
    Add initial support of NURI and SMDKC210 boards
    
    Signed-off-by: Evgeny Voevodin <e.voevodin at samsung.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/Makefile.target b/Makefile.target
index 2b16c0f..c9afbd3 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -344,7 +344,8 @@ obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
 obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
 obj-arm-y += versatile_pci.o
 obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
-obj-arm-y += exynos4210_gic.o exynos4210_combiner.o
+obj-arm-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
+obj-arm-y += exynos4_boards.o
 obj-arm-y += arm_l2x0.o
 obj-arm-y += arm_mptimer.o
 obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
diff --git a/hw/exynos4210.c b/hw/exynos4210.c
new file mode 100644
index 0000000..5b1e24c
--- /dev/null
+++ b/hw/exynos4210.c
@@ -0,0 +1,191 @@
+/*
+ *  Samsung exynos4210 SoC emulation
+ *
+ *  Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *    Maksim Kozlov <m.kozlov at samsung.com>
+ *    Evgeny Voevodin <e.voevodin at samsung.com>
+ *    Igor Mitsyanko  <i.mitsyanko at samsung.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 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 "boards.h"
+#include "sysemu.h"
+#include "sysbus.h"
+#include "arm-misc.h"
+#include "exynos4210.h"
+
+#define EXYNOS4210_CHIPID_ADDR         0x10000000
+
+/* External GIC */
+#define EXYNOS4210_EXT_GIC_CPU_BASE_ADDR    0x10480000
+#define EXYNOS4210_EXT_GIC_DIST_BASE_ADDR   0x10490000
+
+/* Combiner */
+#define EXYNOS4210_EXT_COMBINER_BASE_ADDR   0x10440000
+#define EXYNOS4210_INT_COMBINER_BASE_ADDR   0x10448000
+
+static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43,
+                                    0x09, 0x00, 0x00, 0x00 };
+
+Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
+        unsigned long ram_size)
+{
+    qemu_irq cpu_irq[4];
+    int n;
+    Exynos4210State *s = g_new(Exynos4210State, 1);
+    qemu_irq *irqp;
+    qemu_irq gate_irq[EXYNOS4210_IRQ_GATE_NINPUTS];
+    unsigned long mem_size;
+    DeviceState *dev;
+    SysBusDevice *busdev;
+
+    for (n = 0; n < EXYNOS4210_NCPUS; n++) {
+        s->env[n] = cpu_init("cortex-a9");
+        if (!s->env[n]) {
+            fprintf(stderr, "Unable to find CPU %d definition\n", n);
+            exit(1);
+        }
+        /* Create PIC controller for each processor instance */
+        irqp = arm_pic_init_cpu(s->env[n]);
+
+        /*
+         * Get GICs gpio_in cpu_irq to connect a combiner to them later.
+         * Use only IRQ for a while.
+         */
+        cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
+    }
+
+    /*** IRQs ***/
+
+    s->irq_table = exynos4210_init_irq(&s->irqs);
+
+    /* IRQ Gate */
+    dev = qdev_create(NULL, "exynos4210.irq_gate");
+    qdev_init_nofail(dev);
+    /* Get IRQ Gate input in gate_irq */
+    for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) {
+        gate_irq[n] = qdev_get_gpio_in(dev, n);
+    }
+    busdev = sysbus_from_qdev(dev);
+    /* Connect IRQ Gate output to cpu_irq */
+    for (n = 0; n < EXYNOS4210_NCPUS; n++) {
+        sysbus_connect_irq(busdev, n, cpu_irq[n]);
+    }
+
+    /* Private memory region and Internal GIC */
+    dev = qdev_create(NULL, "a9mpcore_priv");
+    qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
+    qdev_init_nofail(dev);
+    busdev = sysbus_from_qdev(dev);
+    sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR);
+    for (n = 0; n < EXYNOS4210_NCPUS; n++) {
+        sysbus_connect_irq(busdev, n, gate_irq[n * 2]);
+    }
+    for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) {
+        s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    /* Cache controller */
+    sysbus_create_simple("l2x0", EXYNOS4210_L2X0_BASE_ADDR, NULL);
+
+    /* External GIC */
+    dev = qdev_create(NULL, "exynos4210.gic");
+    qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
+    qdev_init_nofail(dev);
+    busdev = sysbus_from_qdev(dev);
+    /* Map CPU interface */
+    sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR);
+    /* Map Distributer interface */
+    sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR);
+    for (n = 0; n < EXYNOS4210_NCPUS; n++) {
+        sysbus_connect_irq(busdev, n, gate_irq[n * 2 + 1]);
+    }
+    for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) {
+        s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    /* Internal Interrupt Combiner */
+    dev = qdev_create(NULL, "exynos4210.combiner");
+    qdev_init_nofail(dev);
+    busdev = sysbus_from_qdev(dev);
+    for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) {
+        sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]);
+    }
+    exynos4210_combiner_get_gpioin(&s->irqs, dev, 0);
+    sysbus_mmio_map(busdev, 0, EXYNOS4210_INT_COMBINER_BASE_ADDR);
+
+    /* External Interrupt Combiner */
+    dev = qdev_create(NULL, "exynos4210.combiner");
+    qdev_prop_set_uint32(dev, "external", 1);
+    qdev_init_nofail(dev);
+    busdev = sysbus_from_qdev(dev);
+    for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) {
+        sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]);
+    }
+    exynos4210_combiner_get_gpioin(&s->irqs, dev, 1);
+    sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_COMBINER_BASE_ADDR);
+
+    /* Initialize board IRQs. */
+    exynos4210_init_board_irqs(&s->irqs);
+
+    /*** Memory ***/
+
+    /* Chip-ID and OMR */
+    memory_region_init_ram_ptr(&s->chipid_mem, "exynos4210.chipid",
+            sizeof(chipid_and_omr), chipid_and_omr);
+    memory_region_set_readonly(&s->chipid_mem, true);
+    memory_region_add_subregion(system_mem, EXYNOS4210_CHIPID_ADDR,
+                                &s->chipid_mem);
+
+    /* Internal ROM */
+    memory_region_init_ram(&s->irom_mem, "exynos4210.irom",
+                           EXYNOS4210_IROM_SIZE);
+    memory_region_set_readonly(&s->irom_mem, true);
+    memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR,
+                                &s->irom_mem);
+    /* mirror of iROM */
+    memory_region_init_alias(&s->irom_alias_mem, "exynos4210.irom_alias",
+                             &s->irom_mem,
+                             EXYNOS4210_IROM_BASE_ADDR,
+                             EXYNOS4210_IROM_SIZE);
+    memory_region_set_readonly(&s->irom_alias_mem, true);
+    memory_region_add_subregion(system_mem, EXYNOS4210_IROM_MIRROR_BASE_ADDR,
+                                &s->irom_alias_mem);
+
+    /* Internal RAM */
+    memory_region_init_ram(&s->iram_mem, "exynos4210.iram",
+                           EXYNOS4210_IRAM_SIZE);
+    vmstate_register_ram_global(&s->iram_mem);
+    memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR,
+                                &s->iram_mem);
+
+    /* DRAM */
+    mem_size = ram_size;
+    if (mem_size > EXYNOS4210_DRAM_MAX_SIZE) {
+        memory_region_init_ram(&s->dram1_mem, "exynos4210.dram1",
+                mem_size - EXYNOS4210_DRAM_MAX_SIZE);
+        vmstate_register_ram_global(&s->dram1_mem);
+        memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR,
+                &s->dram1_mem);
+        mem_size = EXYNOS4210_DRAM_MAX_SIZE;
+    }
+    memory_region_init_ram(&s->dram0_mem, "exynos4210.dram0", mem_size);
+    vmstate_register_ram_global(&s->dram0_mem);
+    memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR,
+            &s->dram0_mem);
+
+    return s;
+}
diff --git a/hw/exynos4210.h b/hw/exynos4210.h
index ef4732f..0026a52 100644
--- a/hw/exynos4210.h
+++ b/hw/exynos4210.h
@@ -31,6 +31,28 @@
 
 #define EXYNOS4210_NCPUS                    2
 
+#define EXYNOS4210_DRAM0_BASE_ADDR          0x40000000
+#define EXYNOS4210_DRAM1_BASE_ADDR          0xa0000000
+#define EXYNOS4210_DRAM_MAX_SIZE            0x60000000  /* 1.5 GB */
+
+#define EXYNOS4210_IROM_BASE_ADDR           0x00000000
+#define EXYNOS4210_IROM_SIZE                0x00010000  /* 64 KB */
+#define EXYNOS4210_IROM_MIRROR_BASE_ADDR    0x02000000
+#define EXYNOS4210_IROM_MIRROR_SIZE         0x00010000  /* 64 KB */
+
+#define EXYNOS4210_IRAM_BASE_ADDR           0x02020000
+#define EXYNOS4210_IRAM_SIZE                0x00020000  /* 128 KB */
+
+/* Secondary CPU startup code is in IROM memory */
+#define EXYNOS4210_SMP_BOOT_ADDR            EXYNOS4210_IROM_BASE_ADDR
+#define EXYNOS4210_SMP_BOOT_SIZE            0x1000
+#define EXYNOS4210_BASE_BOOT_ADDR           EXYNOS4210_DRAM0_BASE_ADDR
+/* Secondary CPU polling address to get loader start from */
+#define EXYNOS4210_SECOND_CPU_BOOTREG       0x10020814
+
+#define EXYNOS4210_SMP_PRIVATE_BASE_ADDR    0x10500000
+#define EXYNOS4210_L2X0_BASE_ADDR           0x10502000
+
 /*
  * exynos4210 IRQ subsystem stub definitions.
  */
@@ -60,6 +82,24 @@ typedef struct Exynos4210Irq {
     qemu_irq board_irqs[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ];
 } Exynos4210Irq;
 
+typedef struct Exynos4210State {
+    CPUState * env[EXYNOS4210_NCPUS];
+    Exynos4210Irq irqs;
+    qemu_irq *irq_table;
+
+    MemoryRegion chipid_mem;
+    MemoryRegion iram_mem;
+    MemoryRegion irom_mem;
+    MemoryRegion irom_alias_mem;
+    MemoryRegion dram0_mem;
+    MemoryRegion dram1_mem;
+    MemoryRegion boot_secondary;
+    MemoryRegion bootreg_mem;
+} Exynos4210State;
+
+Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
+        unsigned long ram_size);
+
 /* Initialize exynos4210 IRQ subsystem stub */
 qemu_irq *exynos4210_init_irq(Exynos4210Irq *env);
 
diff --git a/hw/exynos4_boards.c b/hw/exynos4_boards.c
new file mode 100644
index 0000000..767dc45
--- /dev/null
+++ b/hw/exynos4_boards.c
@@ -0,0 +1,153 @@
+/*
+ *  Samsung exynos4 SoC based boards emulation
+ *
+ *  Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *    Maksim Kozlov <m.kozlov at samsung.com>
+ *    Evgeny Voevodin <e.voevodin at samsung.com>
+ *    Igor Mitsyanko  <i.mitsyanko at samsung.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 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 "sysemu.h"
+#include "sysbus.h"
+#include "arm-misc.h"
+#include "exec-memory.h"
+#include "exynos4210.h"
+#include "boards.h"
+
+#undef DEBUG
+
+//#define DEBUG
+
+#ifdef DEBUG
+    #undef PRINT_DEBUG
+    #define  PRINT_DEBUG(fmt, args...) \
+        do { \
+            fprintf(stderr, "  [%s:%d]   "fmt, __func__, __LINE__, ##args); \
+        } while (0)
+#else
+    #define  PRINT_DEBUG(fmt, args...)  do {} while (0)
+#endif
+
+typedef enum Exynos4BoardType {
+    EXYNOS4_BOARD_NURI,
+    EXYNOS4_BOARD_SMDKC210,
+    EXYNOS4_NUM_OF_BOARDS
+} Exynos4BoardType;
+
+static int exynos4_board_id[EXYNOS4_NUM_OF_BOARDS] = {
+    [EXYNOS4_BOARD_NURI]     = 0xD33,
+    [EXYNOS4_BOARD_SMDKC210] = 0xB16,
+};
+
+static int exynos4_board_smp_bootreg_addr[EXYNOS4_NUM_OF_BOARDS] = {
+    [EXYNOS4_BOARD_NURI]     = EXYNOS4210_SECOND_CPU_BOOTREG,
+    [EXYNOS4_BOARD_SMDKC210] = EXYNOS4210_SECOND_CPU_BOOTREG,
+};
+
+static unsigned long exynos4_board_ram_size[EXYNOS4_NUM_OF_BOARDS] = {
+    [EXYNOS4_BOARD_NURI]     = 0x40000000,
+    [EXYNOS4_BOARD_SMDKC210] = 0x40000000,
+};
+
+static struct arm_boot_info exynos4_board_binfo = {
+    .loader_start     = EXYNOS4210_BASE_BOOT_ADDR,
+    .smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR,
+    .nb_cpus          = EXYNOS4210_NCPUS,
+};
+
+static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS];
+
+static Exynos4210State *exynos4_boards_init_common(
+        const char *kernel_filename,
+        const char *kernel_cmdline,
+        const char *initrd_filename,
+        Exynos4BoardType board_type)
+{
+    if (smp_cpus != EXYNOS4210_NCPUS) {
+        fprintf(stderr, "%s board supports only %d CPU cores. Ignoring smp_cpus"
+                " value.\n",
+                exynos4_machines[board_type].name,
+                exynos4_machines[board_type].max_cpus);
+    }
+
+    exynos4_board_binfo.ram_size = exynos4_board_ram_size[board_type];
+    exynos4_board_binfo.board_id = exynos4_board_id[board_type];
+    exynos4_board_binfo.smp_bootreg_addr =
+            exynos4_board_smp_bootreg_addr[board_type];
+    exynos4_board_binfo.kernel_filename = kernel_filename;
+    exynos4_board_binfo.initrd_filename = initrd_filename;
+    exynos4_board_binfo.kernel_cmdline = kernel_cmdline;
+    exynos4_board_binfo.smp_priv_base = EXYNOS4210_SMP_PRIVATE_BASE_ADDR;
+
+    PRINT_DEBUG("\n ram_size: %luMiB [0x%08lx]\n"
+            " kernel_filename: %s\n"
+            " kernel_cmdline: %s\n"
+            " initrd_filename: %s\n",
+            exynos4_board_ram_size[board_type] / 1048576,
+            exynos4_board_ram_size[board_type],
+            kernel_filename,
+            kernel_cmdline,
+            initrd_filename);
+
+    return exynos4210_init(get_system_memory(),
+            exynos4_board_ram_size[board_type]);
+}
+
+static void nuri_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)
+{
+    exynos4_boards_init_common(kernel_filename, kernel_cmdline,
+                initrd_filename, EXYNOS4_BOARD_NURI);
+
+    arm_load_kernel(first_cpu, &exynos4_board_binfo);
+}
+
+static void smdkc210_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)
+{
+    exynos4_boards_init_common(kernel_filename, kernel_cmdline,
+                initrd_filename, EXYNOS4_BOARD_SMDKC210);
+
+    arm_load_kernel(first_cpu, &exynos4_board_binfo);
+}
+
+static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS] = {
+    [EXYNOS4_BOARD_NURI] = {
+        .name = "nuri",
+        .desc = "Samsung NURI board (Exynos4210)",
+        .init = nuri_init,
+        .max_cpus = EXYNOS4210_NCPUS,
+    },
+    [EXYNOS4_BOARD_SMDKC210] = {
+        .name = "smdkc210",
+        .desc = "Samsung SMDKC210 board (Exynos4210)",
+        .init = smdkc210_init,
+        .max_cpus = EXYNOS4210_NCPUS,
+    },
+};
+
+static void exynos4_machine_init(void)
+{
+    qemu_register_machine(&exynos4_machines[EXYNOS4_BOARD_NURI]);
+    qemu_register_machine(&exynos4_machines[EXYNOS4_BOARD_SMDKC210]);
+}
+
+machine_init(exynos4_machine_init);
commit 8e03cf1eeb1f9e06d281db1d93f92eb25f346f15
Author: Evgeny Voevodin <e.voevodin at samsung.com>
Date:   Thu Feb 16 09:56:04 2012 +0000

    ARM: exynos4210: IRQ subsystem support.
    
    Signed-off-by: Evgeny Voevodin <e.voevodin at samsung.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/Makefile.target b/Makefile.target
index 29fde6e..2b16c0f 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -344,6 +344,7 @@ obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
 obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
 obj-arm-y += versatile_pci.o
 obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
+obj-arm-y += exynos4210_gic.o exynos4210_combiner.o
 obj-arm-y += arm_l2x0.o
 obj-arm-y += arm_mptimer.o
 obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
diff --git a/hw/exynos4210.h b/hw/exynos4210.h
new file mode 100644
index 0000000..ef4732f
--- /dev/null
+++ b/hw/exynos4210.h
@@ -0,0 +1,82 @@
+/*
+ *  Samsung exynos4210 SoC emulation
+ *
+ *  Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *    Maksim Kozlov <m.kozlov at samsung.com>
+ *    Evgeny Voevodin <e.voevodin at samsung.com>
+ *    Igor Mitsyanko <i.mitsyanko at samsung.com>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 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/>.
+ *
+ */
+
+
+#ifndef EXYNOS4210_H_
+#define EXYNOS4210_H_
+
+#include "qemu-common.h"
+#include "memory.h"
+
+#define EXYNOS4210_NCPUS                    2
+
+/*
+ * exynos4210 IRQ subsystem stub definitions.
+ */
+#define EXYNOS4210_IRQ_GATE_NINPUTS 8
+
+#define EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ  64
+#define EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ  16
+#define EXYNOS4210_MAX_INT_COMBINER_IN_IRQ   \
+    (EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ * 8)
+#define EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ   \
+    (EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ * 8)
+
+#define EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit)  ((grp)*8 + (bit))
+#define EXYNOS4210_COMBINER_GET_GRP_NUM(irq)       ((irq) / 8)
+#define EXYNOS4210_COMBINER_GET_BIT_NUM(irq) \
+    ((irq) - 8 * EXYNOS4210_COMBINER_GET_GRP_NUM(irq))
+
+/* IRQs number for external and internal GIC */
+#define EXYNOS4210_EXT_GIC_NIRQ     (160-32)
+#define EXYNOS4210_INT_GIC_NIRQ     64
+
+typedef struct Exynos4210Irq {
+    qemu_irq int_combiner_irq[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ];
+    qemu_irq ext_combiner_irq[EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ];
+    qemu_irq int_gic_irq[EXYNOS4210_INT_GIC_NIRQ];
+    qemu_irq ext_gic_irq[EXYNOS4210_EXT_GIC_NIRQ];
+    qemu_irq board_irqs[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ];
+} Exynos4210Irq;
+
+/* Initialize exynos4210 IRQ subsystem stub */
+qemu_irq *exynos4210_init_irq(Exynos4210Irq *env);
+
+/* Initialize board IRQs.
+ * These IRQs contain splitted Int/External Combiner and External Gic IRQs */
+void exynos4210_init_board_irqs(Exynos4210Irq *s);
+
+/* Get IRQ number from exynos4210 IRQ subsystem stub.
+ * To identify IRQ source use internal combiner group and bit number
+ *  grp - group number
+ *  bit - bit number inside group */
+uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit);
+
+/*
+ * Get Combiner input GPIO into irqs structure
+ */
+void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev,
+        int ext);
+
+#endif /* EXYNOS4210_H_ */
diff --git a/hw/exynos4210_combiner.c b/hw/exynos4210_combiner.c
new file mode 100644
index 0000000..6110c19
--- /dev/null
+++ b/hw/exynos4210_combiner.c
@@ -0,0 +1,469 @@
+/*
+ * Samsung exynos4210 Interrupt Combiner
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ * All rights reserved.
+ *
+ * Evgeny Voevodin <e.voevodin at samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program 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 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/>.
+ */
+
+/*
+ * Exynos4210 Combiner represents an OR gate for SOC's IRQ lines. It combines
+ * IRQ sources into groups and provides signal output to GIC from each group. It
+ * is driven by common mask and enable/disable logic. Take a note that not all
+ * IRQs are passed to GIC through Combiner.
+ */
+
+#include "sysbus.h"
+
+#include "exynos4210.h"
+
+//#define DEBUG_COMBINER
+
+#ifdef DEBUG_COMBINER
+#define DPRINTF(fmt, ...) \
+        do { fprintf(stdout, "COMBINER: [%s:%d] " fmt, __func__ , __LINE__, \
+                ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define    IIC_NGRP        64            /* Internal Interrupt Combiner
+                                            Groups number */
+#define    IIC_NIRQ        (IIC_NGRP * 8)/* Internal Interrupt Combiner
+                                            Interrupts number */
+#define IIC_REGION_SIZE    0x108         /* Size of memory mapped region */
+#define IIC_REGSET_SIZE    0x41
+
+/*
+ * State for each output signal of internal combiner
+ */
+typedef struct CombinerGroupState {
+    uint8_t src_mask;            /* 1 - source enabled, 0 - disabled */
+    uint8_t src_pending;        /* Pending source interrupts before masking */
+} CombinerGroupState;
+
+typedef struct Exynos4210CombinerState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    struct CombinerGroupState group[IIC_NGRP];
+    uint32_t reg_set[IIC_REGSET_SIZE];
+    uint32_t icipsr[2];
+    uint32_t external;          /* 1 means that this combiner is external */
+
+    qemu_irq output_irq[IIC_NGRP];
+} Exynos4210CombinerState;
+
+static const VMStateDescription vmstate_exynos4210_combiner_group_state = {
+    .name = "exynos4210.combiner.groupstate",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(src_mask, CombinerGroupState),
+        VMSTATE_UINT8(src_pending, CombinerGroupState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_exynos4210_combiner = {
+    .name = "exynos4210.combiner",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(group, Exynos4210CombinerState, IIC_NGRP, 0,
+                vmstate_exynos4210_combiner_group_state, CombinerGroupState),
+        VMSTATE_UINT32_ARRAY(reg_set, Exynos4210CombinerState,
+                IIC_REGSET_SIZE),
+        VMSTATE_UINT32_ARRAY(icipsr, Exynos4210CombinerState, 2),
+        VMSTATE_UINT32(external, Exynos4210CombinerState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/*
+ * Get Combiner input GPIO into irqs structure
+ */
+void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev,
+        int ext)
+{
+    int n;
+    int bit;
+    int max;
+    qemu_irq *irq;
+
+    max = ext ? EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ :
+        EXYNOS4210_MAX_INT_COMBINER_IN_IRQ;
+    irq = ext ? irqs->ext_combiner_irq : irqs->int_combiner_irq;
+
+    /*
+     * Some IRQs of Int/External Combiner are going to two Combiners groups,
+     * so let split them.
+     */
+    for (n = 0; n < max; n++) {
+
+        bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n);
+
+        switch (n) {
+        /* MDNIE_LCD1 INTG1 */
+        case EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 0) ...
+             EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 3):
+            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(0, bit + 4)]);
+            continue;
+
+        /* TMU INTG3 */
+        case EXYNOS4210_COMBINER_GET_IRQ_NUM(3, 4):
+            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(2, bit)]);
+            continue;
+
+        /* LCD1 INTG12 */
+        case EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 0) ...
+             EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 3):
+            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(11, bit + 4)]);
+            continue;
+
+        /* Multi-Core Timer INTG12 */
+        case EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4) ...
+             EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 8):
+               irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+                       irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
+            continue;
+
+        /* Multi-Core Timer INTG35 */
+        case EXYNOS4210_COMBINER_GET_IRQ_NUM(35, 4) ...
+             EXYNOS4210_COMBINER_GET_IRQ_NUM(35, 8):
+            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
+            continue;
+
+        /* Multi-Core Timer INTG51 */
+        case EXYNOS4210_COMBINER_GET_IRQ_NUM(51, 4) ...
+             EXYNOS4210_COMBINER_GET_IRQ_NUM(51, 8):
+            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
+            continue;
+
+        /* Multi-Core Timer INTG53 */
+        case EXYNOS4210_COMBINER_GET_IRQ_NUM(53, 4) ...
+             EXYNOS4210_COMBINER_GET_IRQ_NUM(53, 8):
+            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
+            continue;
+        }
+
+        irq[n] = qdev_get_gpio_in(dev, n);
+    }
+}
+
+static uint64_t
+exynos4210_combiner_read(void *opaque, target_phys_addr_t offset, unsigned size)
+{
+    struct Exynos4210CombinerState *s =
+            (struct Exynos4210CombinerState *)opaque;
+    uint32_t req_quad_base_n;    /* Base of registers quad. Multiply it by 4 and
+                                   get a start of corresponding group quad */
+    uint32_t grp_quad_base_n;    /* Base of group quad */
+    uint32_t reg_n;              /* Register number inside the quad */
+    uint32_t val;
+
+    if (s->external && (offset > 0x3c && offset != 0x100)) {
+        hw_error("exynos4210.combiner: unallowed read access at offset 0x"
+                TARGET_FMT_plx "\n", offset);
+    }
+
+    req_quad_base_n = offset >> 4;
+    grp_quad_base_n = req_quad_base_n << 2;
+    reg_n = (offset - (req_quad_base_n << 4)) >> 2;
+
+    if (req_quad_base_n >= IIC_NGRP) {
+        /* Read of ICIPSR register */
+        return s->icipsr[reg_n];
+    }
+
+    val = 0;
+
+    switch (reg_n) {
+    /* IISTR */
+    case 2:
+        val |= s->group[grp_quad_base_n].src_pending;
+        val |= s->group[grp_quad_base_n + 1].src_pending << 8;
+        val |= s->group[grp_quad_base_n + 2].src_pending << 16;
+        val |= s->group[grp_quad_base_n + 3].src_pending << 24;
+        break;
+    /* IIMSR */
+    case 3:
+        val |= s->group[grp_quad_base_n].src_mask &
+        s->group[grp_quad_base_n].src_pending;
+        val |= (s->group[grp_quad_base_n + 1].src_mask &
+                s->group[grp_quad_base_n + 1].src_pending) << 8;
+        val |= (s->group[grp_quad_base_n + 2].src_mask &
+                s->group[grp_quad_base_n + 2].src_pending) << 16;
+        val |= (s->group[grp_quad_base_n + 3].src_mask &
+                s->group[grp_quad_base_n + 3].src_pending) << 24;
+        break;
+    default:
+        if (offset >> 2 >= IIC_REGSET_SIZE) {
+            hw_error("exynos4210.combiner: overflow of reg_set by 0x"
+                    TARGET_FMT_plx "offset\n", offset);
+        }
+        val = s->reg_set[offset >> 2];
+        return 0;
+    }
+    return val;
+}
+
+static void exynos4210_combiner_update(void *opaque, uint8_t group_n)
+{
+    struct Exynos4210CombinerState *s =
+            (struct Exynos4210CombinerState *)opaque;
+
+    /* Send interrupt if needed */
+    if (s->group[group_n].src_mask & s->group[group_n].src_pending) {
+#ifdef DEBUG_COMBINER
+        if (group_n != 26) {
+            /* skip uart */
+            DPRINTF("%s raise IRQ[%d]\n", s->external ? "EXT" : "INT", group_n);
+        }
+#endif
+
+        /* Set Combiner interrupt pending status after masking */
+        if (group_n >= 32) {
+            s->icipsr[1] |= 1 << (group_n - 32);
+        } else {
+            s->icipsr[0] |= 1 << group_n;
+        }
+
+        qemu_irq_raise(s->output_irq[group_n]);
+    } else {
+#ifdef DEBUG_COMBINER
+        if (group_n != 26) {
+            /* skip uart */
+            DPRINTF("%s lower IRQ[%d]\n", s->external ? "EXT" : "INT", group_n);
+        }
+#endif
+
+        /* Set Combiner interrupt pending status after masking */
+        if (group_n >= 32) {
+            s->icipsr[1] &= ~(1 << (group_n - 32));
+        } else {
+            s->icipsr[0] &= ~(1 << group_n);
+        }
+
+        qemu_irq_lower(s->output_irq[group_n]);
+    }
+}
+
+static void exynos4210_combiner_write(void *opaque, target_phys_addr_t offset,
+        uint64_t val, unsigned size)
+{
+    struct Exynos4210CombinerState *s =
+            (struct Exynos4210CombinerState *)opaque;
+    uint32_t req_quad_base_n;    /* Base of registers quad. Multiply it by 4 and
+                                   get a start of corresponding group quad */
+    uint32_t grp_quad_base_n;    /* Base of group quad */
+    uint32_t reg_n;              /* Register number inside the quad */
+
+    if (s->external && (offset > 0x3c && offset != 0x100)) {
+        hw_error("exynos4210.combiner: unallowed write access at offset 0x"
+                TARGET_FMT_plx "\n", offset);
+    }
+
+    req_quad_base_n = offset >> 4;
+    grp_quad_base_n = req_quad_base_n << 2;
+    reg_n = (offset - (req_quad_base_n << 4)) >> 2;
+
+    if (req_quad_base_n >= IIC_NGRP) {
+        hw_error("exynos4210.combiner: unallowed write access at offset 0x"
+                TARGET_FMT_plx "\n", offset);
+        return;
+    }
+
+    if (reg_n > 1) {
+        hw_error("exynos4210.combiner: unallowed write access at offset 0x"
+                TARGET_FMT_plx "\n", offset);
+        return;
+    }
+
+    if (offset >> 2 >= IIC_REGSET_SIZE) {
+        hw_error("exynos4210.combiner: overflow of reg_set by 0x"
+                TARGET_FMT_plx "offset\n", offset);
+    }
+    s->reg_set[offset >> 2] = val;
+
+    switch (reg_n) {
+    /* IIESR */
+    case 0:
+        /* FIXME: what if irq is pending, allowed by mask, and we allow it
+         * again. Interrupt will rise again! */
+
+        DPRINTF("%s enable IRQ for groups %d, %d, %d, %d\n",
+                s->external ? "EXT" : "INT",
+                grp_quad_base_n,
+                grp_quad_base_n + 1,
+                grp_quad_base_n + 2,
+                grp_quad_base_n + 3);
+
+        /* Enable interrupt sources */
+        s->group[grp_quad_base_n].src_mask |= val & 0xFF;
+        s->group[grp_quad_base_n + 1].src_mask |= (val & 0xFF00) >> 8;
+        s->group[grp_quad_base_n + 2].src_mask |= (val & 0xFF0000) >> 16;
+        s->group[grp_quad_base_n + 3].src_mask |= (val & 0xFF000000) >> 24;
+
+        exynos4210_combiner_update(s, grp_quad_base_n);
+        exynos4210_combiner_update(s, grp_quad_base_n + 1);
+        exynos4210_combiner_update(s, grp_quad_base_n + 2);
+        exynos4210_combiner_update(s, grp_quad_base_n + 3);
+        break;
+        /* IIECR */
+    case 1:
+        DPRINTF("%s disable IRQ for groups %d, %d, %d, %d\n",
+                s->external ? "EXT" : "INT",
+                grp_quad_base_n,
+                grp_quad_base_n + 1,
+                grp_quad_base_n + 2,
+                grp_quad_base_n + 3);
+
+        /* Disable interrupt sources */
+        s->group[grp_quad_base_n].src_mask &= ~(val & 0xFF);
+        s->group[grp_quad_base_n + 1].src_mask &= ~((val & 0xFF00) >> 8);
+        s->group[grp_quad_base_n + 2].src_mask &= ~((val & 0xFF0000) >> 16);
+        s->group[grp_quad_base_n + 3].src_mask &= ~((val & 0xFF000000) >> 24);
+
+        exynos4210_combiner_update(s, grp_quad_base_n);
+        exynos4210_combiner_update(s, grp_quad_base_n + 1);
+        exynos4210_combiner_update(s, grp_quad_base_n + 2);
+        exynos4210_combiner_update(s, grp_quad_base_n + 3);
+        break;
+    default:
+        hw_error("exynos4210.combiner: unallowed write access at offset 0x"
+                TARGET_FMT_plx "\n", offset);
+        break;
+    }
+
+    return;
+}
+
+/* Get combiner group and bit from irq number */
+static uint8_t get_combiner_group_and_bit(int irq, uint8_t *bit)
+{
+    *bit = irq - ((irq >> 3) << 3);
+    return irq >> 3;
+}
+
+/* Process a change in an external IRQ input.  */
+static void exynos4210_combiner_handler(void *opaque, int irq, int level)
+{
+    struct Exynos4210CombinerState *s =
+            (struct Exynos4210CombinerState *)opaque;
+    uint8_t bit_n, group_n;
+
+    group_n = get_combiner_group_and_bit(irq, &bit_n);
+
+    if (s->external && group_n >= EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ) {
+        DPRINTF("%s unallowed IRQ group 0x%x\n", s->external ? "EXT" : "INT"
+                , group_n);
+        return;
+    }
+
+    if (level) {
+        s->group[group_n].src_pending |= 1 << bit_n;
+    } else {
+        s->group[group_n].src_pending &= ~(1 << bit_n);
+    }
+
+    exynos4210_combiner_update(s, group_n);
+
+    return;
+}
+
+static void exynos4210_combiner_reset(DeviceState *d)
+{
+    struct Exynos4210CombinerState *s = (struct Exynos4210CombinerState *)d;
+
+    memset(&s->group, 0, sizeof(s->group));
+    memset(&s->reg_set, 0, sizeof(s->reg_set));
+
+    s->reg_set[0xC0 >> 2] = 0x01010101;
+    s->reg_set[0xC4 >> 2] = 0x01010101;
+    s->reg_set[0xD0 >> 2] = 0x01010101;
+    s->reg_set[0xD4 >> 2] = 0x01010101;
+}
+
+static const MemoryRegionOps exynos4210_combiner_ops = {
+    .read = exynos4210_combiner_read,
+    .write = exynos4210_combiner_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/*
+ * Internal Combiner initialization.
+ */
+static int exynos4210_combiner_init(SysBusDevice *dev)
+{
+    unsigned int i;
+    struct Exynos4210CombinerState *s =
+            FROM_SYSBUS(struct Exynos4210CombinerState, dev);
+
+    /* Allocate general purpose input signals and connect a handler to each of
+     * them */
+    qdev_init_gpio_in(&s->busdev.qdev, exynos4210_combiner_handler, IIC_NIRQ);
+
+    /* Connect SysBusDev irqs to device specific irqs */
+    for (i = 0; i < IIC_NIRQ; i++) {
+        sysbus_init_irq(dev, &s->output_irq[i]);
+    }
+
+    memory_region_init_io(&s->iomem, &exynos4210_combiner_ops, s,
+            "exynos4210-combiner", IIC_REGION_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static Property exynos4210_combiner_properties[] = {
+    DEFINE_PROP_UINT32("external", Exynos4210CombinerState, external, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void exynos4210_combiner_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = exynos4210_combiner_init;
+    dc->reset = exynos4210_combiner_reset;
+    dc->props = exynos4210_combiner_properties;
+    dc->vmsd = &vmstate_exynos4210_combiner;
+}
+
+static TypeInfo exynos4210_combiner_info = {
+    .name          = "exynos4210.combiner",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210CombinerState),
+    .class_init    = exynos4210_combiner_class_init,
+};
+
+static void exynos4210_combiner_register_types(void)
+{
+    type_register_static(&exynos4210_combiner_info);
+}
+
+type_init(exynos4210_combiner_register_types)
diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c
new file mode 100644
index 0000000..ec13140
--- /dev/null
+++ b/hw/exynos4210_gic.c
@@ -0,0 +1,458 @@
+/*
+ * Samsung exynos4210 GIC implementation. Based on hw/arm_gic.c
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ * All rights reserved.
+ *
+ * Evgeny Voevodin <e.voevodin at samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program 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 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 "qemu-common.h"
+#include "irq.h"
+#include "exynos4210.h"
+
+enum ExtGicId {
+    EXT_GIC_ID_MDMA_LCD0 = 66,
+    EXT_GIC_ID_PDMA0,
+    EXT_GIC_ID_PDMA1,
+    EXT_GIC_ID_TIMER0,
+    EXT_GIC_ID_TIMER1,
+    EXT_GIC_ID_TIMER2,
+    EXT_GIC_ID_TIMER3,
+    EXT_GIC_ID_TIMER4,
+    EXT_GIC_ID_MCT_L0,
+    EXT_GIC_ID_WDT,
+    EXT_GIC_ID_RTC_ALARM,
+    EXT_GIC_ID_RTC_TIC,
+    EXT_GIC_ID_GPIO_XB,
+    EXT_GIC_ID_GPIO_XA,
+    EXT_GIC_ID_MCT_L1,
+    EXT_GIC_ID_IEM_APC,
+    EXT_GIC_ID_IEM_IEC,
+    EXT_GIC_ID_NFC,
+    EXT_GIC_ID_UART0,
+    EXT_GIC_ID_UART1,
+    EXT_GIC_ID_UART2,
+    EXT_GIC_ID_UART3,
+    EXT_GIC_ID_UART4,
+    EXT_GIC_ID_MCT_G0,
+    EXT_GIC_ID_I2C0,
+    EXT_GIC_ID_I2C1,
+    EXT_GIC_ID_I2C2,
+    EXT_GIC_ID_I2C3,
+    EXT_GIC_ID_I2C4,
+    EXT_GIC_ID_I2C5,
+    EXT_GIC_ID_I2C6,
+    EXT_GIC_ID_I2C7,
+    EXT_GIC_ID_SPI0,
+    EXT_GIC_ID_SPI1,
+    EXT_GIC_ID_SPI2,
+    EXT_GIC_ID_MCT_G1,
+    EXT_GIC_ID_USB_HOST,
+    EXT_GIC_ID_USB_DEVICE,
+    EXT_GIC_ID_MODEMIF,
+    EXT_GIC_ID_HSMMC0,
+    EXT_GIC_ID_HSMMC1,
+    EXT_GIC_ID_HSMMC2,
+    EXT_GIC_ID_HSMMC3,
+    EXT_GIC_ID_SDMMC,
+    EXT_GIC_ID_MIPI_CSI_4LANE,
+    EXT_GIC_ID_MIPI_DSI_4LANE,
+    EXT_GIC_ID_MIPI_CSI_2LANE,
+    EXT_GIC_ID_MIPI_DSI_2LANE,
+    EXT_GIC_ID_ONENAND_AUDI,
+    EXT_GIC_ID_ROTATOR,
+    EXT_GIC_ID_FIMC0,
+    EXT_GIC_ID_FIMC1,
+    EXT_GIC_ID_FIMC2,
+    EXT_GIC_ID_FIMC3,
+    EXT_GIC_ID_JPEG,
+    EXT_GIC_ID_2D,
+    EXT_GIC_ID_PCIe,
+    EXT_GIC_ID_MIXER,
+    EXT_GIC_ID_HDMI,
+    EXT_GIC_ID_HDMI_I2C,
+    EXT_GIC_ID_MFC,
+    EXT_GIC_ID_TVENC,
+};
+
+enum ExtInt {
+    EXT_GIC_ID_EXTINT0 = 48,
+    EXT_GIC_ID_EXTINT1,
+    EXT_GIC_ID_EXTINT2,
+    EXT_GIC_ID_EXTINT3,
+    EXT_GIC_ID_EXTINT4,
+    EXT_GIC_ID_EXTINT5,
+    EXT_GIC_ID_EXTINT6,
+    EXT_GIC_ID_EXTINT7,
+    EXT_GIC_ID_EXTINT8,
+    EXT_GIC_ID_EXTINT9,
+    EXT_GIC_ID_EXTINT10,
+    EXT_GIC_ID_EXTINT11,
+    EXT_GIC_ID_EXTINT12,
+    EXT_GIC_ID_EXTINT13,
+    EXT_GIC_ID_EXTINT14,
+    EXT_GIC_ID_EXTINT15
+};
+
+/*
+ * External GIC sources which are not from External Interrupt Combiner or
+ * External Interrupts are starting from EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ,
+ * which is INTG16 in Internal Interrupt Combiner.
+ */
+
+static uint32_t
+combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = {
+    /* int combiner groups 16-19 */
+    { }, { }, { }, { },
+    /* int combiner group 20 */
+    { 0, EXT_GIC_ID_MDMA_LCD0 },
+    /* int combiner group 21 */
+    { EXT_GIC_ID_PDMA0, EXT_GIC_ID_PDMA1 },
+    /* int combiner group 22 */
+    { EXT_GIC_ID_TIMER0, EXT_GIC_ID_TIMER1, EXT_GIC_ID_TIMER2,
+            EXT_GIC_ID_TIMER3, EXT_GIC_ID_TIMER4 },
+    /* int combiner group 23 */
+    { EXT_GIC_ID_RTC_ALARM, EXT_GIC_ID_RTC_TIC },
+    /* int combiner group 24 */
+    { EXT_GIC_ID_GPIO_XB, EXT_GIC_ID_GPIO_XA },
+    /* int combiner group 25 */
+    { EXT_GIC_ID_IEM_APC, EXT_GIC_ID_IEM_IEC },
+    /* int combiner group 26 */
+    { EXT_GIC_ID_UART0, EXT_GIC_ID_UART1, EXT_GIC_ID_UART2, EXT_GIC_ID_UART3,
+            EXT_GIC_ID_UART4 },
+    /* int combiner group 27 */
+    { EXT_GIC_ID_I2C0, EXT_GIC_ID_I2C1, EXT_GIC_ID_I2C2, EXT_GIC_ID_I2C3,
+            EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6,
+            EXT_GIC_ID_I2C7 },
+    /* int combiner group 28 */
+    { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 },
+    /* int combiner group 29 */
+    { EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2,
+     EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC },
+    /* int combiner group 30 */
+    { EXT_GIC_ID_MIPI_CSI_4LANE, EXT_GIC_ID_MIPI_CSI_2LANE },
+    /* int combiner group 31 */
+    { EXT_GIC_ID_MIPI_DSI_4LANE, EXT_GIC_ID_MIPI_DSI_2LANE },
+    /* int combiner group 32 */
+    { EXT_GIC_ID_FIMC0, EXT_GIC_ID_FIMC1 },
+    /* int combiner group 33 */
+    { EXT_GIC_ID_FIMC2, EXT_GIC_ID_FIMC3 },
+    /* int combiner group 34 */
+    { EXT_GIC_ID_ONENAND_AUDI, EXT_GIC_ID_NFC },
+    /* int combiner group 35 */
+    { 0, 0, 0, EXT_GIC_ID_MCT_L1, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
+    /* int combiner group 36 */
+    { EXT_GIC_ID_MIXER },
+    /* int combiner group 37 */
+    { EXT_GIC_ID_EXTINT4, EXT_GIC_ID_EXTINT5, EXT_GIC_ID_EXTINT6,
+     EXT_GIC_ID_EXTINT7 },
+    /* groups 38-50 */
+    { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { },
+    /* int combiner group 51 */
+    { EXT_GIC_ID_MCT_L0, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
+    /* group 52 */
+    { },
+    /* int combiner group 53 */
+    { EXT_GIC_ID_WDT, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
+    /* groups 54-63 */
+    { }, { }, { }, { }, { }, { }, { }, { }, { }, { }
+};
+
+#define EXYNOS4210_GIC_NIRQ 160
+#define NCPU                EXYNOS4210_NCPUS
+
+#define EXYNOS4210_EXT_GIC_CPU_REGION_SIZE     0x10000
+#define EXYNOS4210_EXT_GIC_DIST_REGION_SIZE    0x10000
+
+#define EXYNOS4210_EXT_GIC_PER_CPU_OFFSET      0x8000
+#define EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(n) \
+    ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET)
+#define EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(n) \
+    ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET)
+
+#define EXYNOS4210_GIC_CPU_REGION_SIZE  0x100
+#define EXYNOS4210_GIC_DIST_REGION_SIZE 0x1000
+
+static void exynos4210_irq_handler(void *opaque, int irq, int level)
+{
+    Exynos4210Irq *s = (Exynos4210Irq *)opaque;
+
+    /* Bypass */
+    qemu_set_irq(s->board_irqs[irq], level);
+
+    return;
+}
+
+/*
+ * Initialize exynos4210 IRQ subsystem stub.
+ */
+qemu_irq *exynos4210_init_irq(Exynos4210Irq *s)
+{
+    return qemu_allocate_irqs(exynos4210_irq_handler, s,
+            EXYNOS4210_MAX_INT_COMBINER_IN_IRQ);
+}
+
+/*
+ * Initialize board IRQs.
+ * These IRQs contain splitted Int/External Combiner and External Gic IRQs.
+ */
+void exynos4210_init_board_irqs(Exynos4210Irq *s)
+{
+    uint32_t grp, bit, irq_id, n;
+
+    for (n = 0; n < EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ; n++) {
+        s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
+                s->ext_combiner_irq[n]);
+
+        irq_id = 0;
+        if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 4) ||
+                n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4)) {
+            /* MCT_G0 is passed to External GIC */
+            irq_id = EXT_GIC_ID_MCT_G0;
+        }
+        if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 5) ||
+                n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 5)) {
+            /* MCT_G1 is passed to External and GIC */
+            irq_id = EXT_GIC_ID_MCT_G1;
+        }
+        if (irq_id) {
+            s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
+                    s->ext_gic_irq[irq_id-32]);
+        }
+
+    }
+    for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) {
+        /* these IDs are passed to Internal Combiner and External GIC */
+        grp = EXYNOS4210_COMBINER_GET_GRP_NUM(n);
+        bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n);
+        irq_id = combiner_grp_to_gic_id[grp -
+                     EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][bit];
+
+        if (irq_id) {
+            s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
+                    s->ext_gic_irq[irq_id-32]);
+        }
+    }
+}
+
+/*
+ * Get IRQ number from exynos4210 IRQ subsystem stub.
+ * To identify IRQ source use internal combiner group and bit number
+ *  grp - group number
+ *  bit - bit number inside group
+ */
+uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit)
+{
+    return EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit);
+}
+
+/********* GIC part *********/
+
+static inline int
+gic_get_current_cpu(void)
+{
+    return cpu_single_env->cpu_index;
+}
+
+#include "arm_gic.c"
+
+typedef struct {
+    gic_state gic;
+    MemoryRegion cpu_container;
+    MemoryRegion dist_container;
+    MemoryRegion cpu_alias[NCPU];
+    MemoryRegion dist_alias[NCPU];
+    uint32_t num_cpu;
+} Exynos4210GicState;
+
+static int exynos4210_gic_init(SysBusDevice *dev)
+{
+    Exynos4210GicState *s = FROM_SYSBUSGIC(Exynos4210GicState, dev);
+    uint32_t i;
+    const char cpu_prefix[] = "exynos4210-gic-alias_cpu";
+    const char dist_prefix[] = "exynos4210-gic-alias_dist";
+    char cpu_alias_name[sizeof(cpu_prefix) + 3];
+    char dist_alias_name[sizeof(cpu_prefix) + 3];
+
+    gic_init(&s->gic, s->num_cpu, EXYNOS4210_GIC_NIRQ);
+
+    memory_region_init(&s->cpu_container, "exynos4210-cpu-container",
+            EXYNOS4210_EXT_GIC_CPU_REGION_SIZE);
+    memory_region_init(&s->dist_container, "exynos4210-dist-container",
+            EXYNOS4210_EXT_GIC_DIST_REGION_SIZE);
+
+    for (i = 0; i < s->num_cpu; i++) {
+        /* Map CPU interface per SMP Core */
+        sprintf(cpu_alias_name, "%s%x", cpu_prefix, i);
+        memory_region_init_alias(&s->cpu_alias[i],
+                                 cpu_alias_name,
+                                 &s->gic.cpuiomem[0],
+                                 0,
+                                 EXYNOS4210_GIC_CPU_REGION_SIZE);
+        memory_region_add_subregion(&s->cpu_container,
+                EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(i), &s->cpu_alias[i]);
+
+        /* Map Distributor per SMP Core */
+        sprintf(dist_alias_name, "%s%x", dist_prefix, i);
+        memory_region_init_alias(&s->dist_alias[i],
+                                 dist_alias_name,
+                                 &s->gic.iomem,
+                                 0,
+                                 EXYNOS4210_GIC_DIST_REGION_SIZE);
+        memory_region_add_subregion(&s->dist_container,
+                EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(i), &s->dist_alias[i]);
+    }
+
+    sysbus_init_mmio(dev, &s->cpu_container);
+    sysbus_init_mmio(dev, &s->dist_container);
+
+    gic_cpu_write(&s->gic, 1, 0, 1);
+
+    return 0;
+}
+
+static Property exynos4210_gic_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", Exynos4210GicState, num_cpu, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void exynos4210_gic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = exynos4210_gic_init;
+    dc->props = exynos4210_gic_properties;
+}
+
+static TypeInfo exynos4210_gic_info = {
+    .name          = "exynos4210.gic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210GicState),
+    .class_init    = exynos4210_gic_class_init,
+};
+
+static void exynos4210_gic_register_types(void)
+{
+    type_register_static(&exynos4210_gic_info);
+}
+
+type_init(exynos4210_gic_register_types)
+
+/*
+ * IRQGate struct.
+ * IRQ Gate represents OR gate between GICs to pass IRQ to PIC.
+ */
+typedef struct {
+    SysBusDevice busdev;
+
+    qemu_irq pic_irq[NCPU]; /* output IRQs to PICs */
+    uint32_t gpio_level[EXYNOS4210_IRQ_GATE_NINPUTS]; /* Input levels */
+} Exynos4210IRQGateState;
+
+static const VMStateDescription vmstate_exynos4210_irq_gate = {
+    .name = "exynos4210.irq_gate",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(gpio_level, Exynos4210IRQGateState,
+                EXYNOS4210_IRQ_GATE_NINPUTS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* Process a change in an external IRQ input.  */
+static void exynos4210_irq_gate_handler(void *opaque, int irq, int level)
+{
+    Exynos4210IRQGateState *s =
+            (Exynos4210IRQGateState *)opaque;
+    uint32_t odd, even;
+
+    if (irq & 1) {
+        odd = irq;
+        even = irq & ~1;
+    } else {
+        even = irq;
+        odd = irq | 1;
+    }
+
+    assert(irq < EXYNOS4210_IRQ_GATE_NINPUTS);
+    s->gpio_level[irq] = level;
+
+    if (s->gpio_level[odd] >= 1 || s->gpio_level[even] >= 1) {
+        qemu_irq_raise(s->pic_irq[even >> 1]);
+    } else {
+        qemu_irq_lower(s->pic_irq[even >> 1]);
+    }
+
+    return;
+}
+
+static void exynos4210_irq_gate_reset(DeviceState *d)
+{
+    Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)d;
+
+    memset(&s->gpio_level, 0, sizeof(s->gpio_level));
+}
+
+/*
+ * IRQ Gate initialization.
+ */
+static int exynos4210_irq_gate_init(SysBusDevice *dev)
+{
+    unsigned int i;
+    Exynos4210IRQGateState *s =
+            FROM_SYSBUS(Exynos4210IRQGateState, dev);
+
+    /* Allocate general purpose input signals and connect a handler to each of
+     * them */
+    qdev_init_gpio_in(&s->busdev.qdev, exynos4210_irq_gate_handler,
+            EXYNOS4210_IRQ_GATE_NINPUTS);
+
+    /* Connect SysBusDev irqs to device specific irqs */
+    for (i = 0; i < NCPU; i++) {
+        sysbus_init_irq(dev, &s->pic_irq[i]);
+    }
+
+    return 0;
+}
+
+static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = exynos4210_irq_gate_init;
+    dc->reset = exynos4210_irq_gate_reset;
+    dc->vmsd = &vmstate_exynos4210_irq_gate;
+}
+
+static TypeInfo exynos4210_irq_gate_info = {
+    .name          = "exynos4210.irq_gate",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210IRQGateState),
+    .class_init    = exynos4210_irq_gate_class_init,
+};
+
+static void exynos4210_irq_gate_register_types(void)
+{
+    type_register_static(&exynos4210_irq_gate_info);
+}
+
+type_init(exynos4210_irq_gate_register_types)
commit 9de36b1a7cf61aa8be365f13c81668b3e19fbc7f
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Feb 8 05:41:38 2012 +0000

    Make -machine/-enable-kvm options merge into a single list
    
    Make the "machine" option list use list merging, so that multiple
    -machine arguments (and the -enable-kvm argument) all merge together
    into a single list. Drop the calls to qemu_opts_reset() which meant
    that only the last -machine or -enable-kvm option had any effect.
    
    This fixes the bug where "-enable-kvm -machine foo" would ignore
    the '-enable-kvm' option, and "-machine foo -enable-kvm" would
    ignore the '-machine foo' option.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>

diff --git a/qemu-config.c b/qemu-config.c
index 12f5c27..c9763e0 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -547,6 +547,7 @@ QemuOptsList qemu_option_rom_opts = {
 static QemuOptsList qemu_machine_opts = {
     .name = "machine",
     .implied_opt_name = "type",
+    .merge_lists = true,
     .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head),
     .desc = {
         {
diff --git a/vl.c b/vl.c
index 0e8425e..37f2f96 100644
--- a/vl.c
+++ b/vl.c
@@ -2882,12 +2882,10 @@ int main(int argc, char **argv, char **envp)
                 break;
             case QEMU_OPTION_enable_kvm:
                 olist = qemu_find_opts("machine");
-                qemu_opts_reset(olist);
                 qemu_opts_parse(olist, "accel=kvm", 0);
                 break;
             case QEMU_OPTION_machine:
                 olist = qemu_find_opts("machine");
-                qemu_opts_reset(olist);
                 opts = qemu_opts_parse(olist, optarg, 1);
                 if (!opts) {
                     fprintf(stderr, "parse error: %s\n", optarg);
commit da93318a9f0ff83e4a93e8755fa92291f9b8cc1b
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Feb 8 05:41:37 2012 +0000

    qemu-option: Add support for merged QemuOptsLists
    
    Add support for option lists which are merged together, so that
    "-listname foo=bar -listname bar=baz" is equivalent to "-listname
    foo=bar,bar=baz" rather than generating two separate lists of options.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>

diff --git a/qemu-option.c b/qemu-option.c
index 4626ccf..35cd609 100644
--- a/qemu-option.c
+++ b/qemu-option.c
@@ -741,13 +741,18 @@ QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exist
         }
         opts = qemu_opts_find(list, id);
         if (opts != NULL) {
-            if (fail_if_exists) {
+            if (fail_if_exists && !list->merge_lists) {
                 qerror_report(QERR_DUPLICATE_ID, id, list->name);
                 return NULL;
             } else {
                 return opts;
             }
         }
+    } else if (list->merge_lists) {
+        opts = qemu_opts_find(list, NULL);
+        if (opts) {
+            return opts;
+        }
     }
     opts = g_malloc0(sizeof(*opts));
     if (id) {
diff --git a/qemu-option.h b/qemu-option.h
index e6f61e6..3ca00c3 100644
--- a/qemu-option.h
+++ b/qemu-option.h
@@ -100,6 +100,7 @@ typedef struct QemuOptDesc {
 struct QemuOptsList {
     const char *name;
     const char *implied_opt_name;
+    bool merge_lists;  /* Merge multiple uses of option into a single list? */
     QTAILQ_HEAD(, QemuOpts) head;
     QemuOptDesc desc[];
 };
commit a84fac1426acd56f6dff4f6023611c1aefe748de
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Feb 1 17:23:04 2012 +0000

    target-arm/helper.c: tb_flush() on CPU reset
    
    Since target-arm has some CPUState fields for which we take the approach
    of baking assumptions about them into translated code and then calling
    tb_flush() when the fields change, we must also tb_flush on CPU reset,
    because reset is a change of those fields.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 34b226e..4929372 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -344,6 +344,11 @@ void cpu_reset(CPUARMState *env)
     set_float_detect_tininess(float_tininess_before_rounding,
                               &env->vfp.standard_fp_status);
     tlb_flush(env, 1);
+    /* Reset is a state change for some CPUState fields which we
+     * bake assumptions about into translated code, so we need to
+     * tb_flush().
+     */
+    tb_flush(env);
 }
 
 static int vfp_gdb_get_reg(CPUState *env, uint8_t *buf, int reg)
commit 761c9eb0fafa59821e3ded9e4d5b33d5ab8a0e9e
Author: Stefan Weil <sw at weilnetz.de>
Date:   Sun Jan 29 08:52:15 2012 +0100

    hw/arm: Remove redundant arguments from set_kernel_args*
    
    The parameters initrd_size and base are already included
    in the info parameter, so there is no need to pass them
    separately.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>,

diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index 5f163fd..34a8739 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -81,9 +81,10 @@ static void default_reset_secondary(CPUState *env,
     p += 4;                       \
 } while (0)
 
-static void set_kernel_args(const struct arm_boot_info *info,
-                int initrd_size, target_phys_addr_t base)
+static void set_kernel_args(const struct arm_boot_info *info)
 {
+    int initrd_size = info->initrd_size;
+    target_phys_addr_t base = info->loader_start;
     target_phys_addr_t p;
 
     p = base + KERNEL_ARGS_ADDR;
@@ -134,12 +135,12 @@ static void set_kernel_args(const struct arm_boot_info *info,
     WRITE_WORD(p, 0);
 }
 
-static void set_kernel_args_old(const struct arm_boot_info *info,
-                int initrd_size, target_phys_addr_t base)
+static void set_kernel_args_old(const struct arm_boot_info *info)
 {
     target_phys_addr_t p;
     const char *s;
-
+    int initrd_size = info->initrd_size;
+    target_phys_addr_t base = info->loader_start;
 
     /* see linux/include/asm-arm/setup.h */
     p = base + KERNEL_ARGS_ADDR;
@@ -222,11 +223,9 @@ static void do_cpu_reset(void *opaque)
             if (env == first_cpu) {
                 env->regs[15] = info->loader_start;
                 if (old_param) {
-                    set_kernel_args_old(info, info->initrd_size,
-                                        info->loader_start);
+                    set_kernel_args_old(info);
                 } else {
-                    set_kernel_args(info, info->initrd_size,
-                                    info->loader_start);
+                    set_kernel_args(info);
                 }
             } else {
                 info->secondary_cpu_reset_hook(env, info);
commit 4f56da61b907ef33fedeed78cf9299f6219c45e2
Author: Vasily Khoruzhick <anarsoul at gmail.com>
Date:   Tue Jan 24 22:32:30 2012 +0300

    pxa2xx_lcd: SRAM is valid location for the framebuffer
    
    Signed-off-by: Vasily Khoruzhick <anarsoul at gmail.com>
    Signed-off-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>

diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c
index 4e9f7b4..9495226 100644
--- a/hw/pxa2xx_lcd.c
+++ b/hw/pxa2xx_lcd.c
@@ -308,9 +308,12 @@ static void pxa2xx_descriptor_load(PXA2xxLCDState *s)
         } else
             descptr = s->dma_ch[i].descriptor;
 
-        if (!(descptr >= PXA2XX_SDRAM_BASE && descptr +
-                    sizeof(desc) <= PXA2XX_SDRAM_BASE + ram_size))
+        if (!((descptr >= PXA2XX_SDRAM_BASE && descptr +
+                 sizeof(desc) <= PXA2XX_SDRAM_BASE + ram_size) ||
+                (descptr >= PXA2XX_INTERNAL_BASE && descptr + sizeof(desc) <=
+                 PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) {
             continue;
+        }
 
         cpu_physical_memory_read(descptr, (void *)&desc, sizeof(desc));
         s->dma_ch[i].descriptor = tswap32(desc.fdaddr);
@@ -830,8 +833,10 @@ static void pxa2xx_update_display(void *opaque)
                 continue;
             }
             fbptr = s->dma_ch[ch].source;
-            if (!(fbptr >= PXA2XX_SDRAM_BASE &&
-                    fbptr <= PXA2XX_SDRAM_BASE + ram_size)) {
+            if (!((fbptr >= PXA2XX_SDRAM_BASE &&
+                     fbptr <= PXA2XX_SDRAM_BASE + ram_size) ||
+                    (fbptr >= PXA2XX_INTERNAL_BASE &&
+                     fbptr <= PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) {
                 pxa2xx_dma_ber_set(s, ch);
                 continue;
             }
commit 2d2624a001010548e3e170d812e0f116b78501aa
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Feb 7 17:56:57 2012 +0000

    target-arm/helper.c: Correct FPSID value for Cortex-A9
    
    The correct FPSID for the Cortex-A9 (according to the TRM) is
    0x41033090 for the r0p0 that we claim to model.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index ea4f35f..34b226e 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -157,7 +157,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
          * and valid configurations; we don't model A9UP).
          */
         set_feature(env, ARM_FEATURE_V7MP);
-        env->vfp.xregs[ARM_VFP_FPSID] = 0x41034000; /* Guess */
+        env->vfp.xregs[ARM_VFP_FPSID] = 0x41033090;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x01111111;
         memcpy(env->cp15.c0_c1, cortexa9_cp15_c0_c1, 8 * sizeof(uint32_t));
commit dd4427a6194eb4efd38542737a053ca474039a76
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Jan 20 12:10:34 2012 +0100

    nseries: attach monitor powerdown request to menelaus
    
    I noticed some unused code in the twl92230, probably from before
    qdev-ification.  This patch makes the machine use the chip's pwrbtn
    signal.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>

diff --git a/hw/nseries.c b/hw/nseries.c
index d429dbd..c5b3184 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -204,6 +204,8 @@ static void n8x0_i2c_setup(struct n800_s *s)
                           qdev_get_gpio_in(s->cpu->ih[0],
                                            OMAP_INT_24XX_SYS_NIRQ));
 
+    qemu_system_powerdown = qdev_get_gpio_in(dev, 3);
+
     /* Attach a TMP105 PM chip (A0 wired to ground) */
     dev = i2c_create_slave(s->i2c, "tmp105", N8X0_TMP105_ADDR);
     qdev_connect_gpio_out(dev, 0, tmp_irq);
diff --git a/hw/twl92230.c b/hw/twl92230.c
index 873dc8f..22da6f8 100644
--- a/hw/twl92230.c
+++ b/hw/twl92230.c
@@ -61,9 +61,7 @@ typedef struct {
     } rtc;
     uint16_t rtc_next_vmstate;
     qemu_irq out[4];
-    qemu_irq *in;
     uint8_t pwrbtn_state;
-    qemu_irq pwrbtn;
 } MenelausState;
 
 static inline void menelaus_update(MenelausState *s)
@@ -186,14 +184,12 @@ static void menelaus_gpio_set(void *opaque, int line, int level)
 {
     MenelausState *s = (MenelausState *) opaque;
 
-    /* No interrupt generated */
-    s->inputs &= ~(1 << line);
-    s->inputs |= level << line;
-}
-
-static void menelaus_pwrbtn_set(void *opaque, int line, int level)
-{
-    MenelausState *s = (MenelausState *) opaque;
+    if (line < 3) {
+        /* No interrupt generated */
+        s->inputs &= ~(1 << line);
+        s->inputs |= level << line;
+        return;
+    }
 
     if (!s->pwrbtn_state && level) {
         s->status |= 1 << 11;					/* PSHBTN */
@@ -849,8 +845,9 @@ static int twl92230_init(I2CSlave *i2c)
     s->rtc.hz_tm = qemu_new_timer_ms(rt_clock, menelaus_rtc_hz, s);
     /* Three output pins plus one interrupt pin.  */
     qdev_init_gpio_out(&i2c->qdev, s->out, 4);
-    qdev_init_gpio_in(&i2c->qdev, menelaus_gpio_set, 3);
-    s->pwrbtn = qemu_allocate_irqs(menelaus_pwrbtn_set, s, 1)[0];
+
+    /* Three input pins plus one power-button pin.  */
+    qdev_init_gpio_in(&i2c->qdev, menelaus_gpio_set, 4);
 
     menelaus_reset(&s->i2c);
 
commit 6c263e26a5c162a8cd79e32bb82422697db5c57c
Merge: cf5cfe0... a4aecd2...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 15 18:41:28 2012 -0600

    Merge remote-tracking branch 'qemu-kvm/uq/master' into staging
    
    * qemu-kvm/uq/master:
      apic: Fix legacy vmstate loading for KVM
      kvm: Implement kvm_irqchip_in_kernel like kvm_enabled
      kvm: Allow to set shadow MMU size

commit cf5cfe0471eb3693401f390bc467413d14dce368
Merge: 006c891... 7bc9318...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 15 18:40:53 2012 -0600

    Merge remote-tracking branch 'kraxel/vnc.2' into staging
    
    * kraxel/vnc.2:
      vnc: lift modifier keys on client disconnect.
      vnc: implement shared flag handling.
      vnc: fix ctrl key in vnc terminal emulation
      Fix vnc memory corruption with width = 1400

commit 006c891fc9d4f044ad3f41b6e019442523b45a54
Merge: 7718564... 6612db1...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 15 18:40:26 2012 -0600

    Merge remote-tracking branch 'kiszka/queues/slirp' into staging
    
    * kiszka/queues/slirp:
      slirp: Prevent sending ICMP error replies to source-only addresses
      slirp: Remove unused variable and unused code

commit 7718564ba1295f35188a5fb3ac8633c29d43b166
Merge: 65b31cc... 7c605a2...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 15 17:25:25 2012 -0600

    Merge remote-tracking branch 'kraxel/usb.38' into staging
    
    * kraxel/usb.38: (28 commits)
      xhci: handle USB_RET_NAK
      xhci: remote wakeup support
      xhci: kill port arg from xhci_setup_packet
      xhci: stop on errors
      xhci: add trb type name lookup support.
      xhci: signal low- and fullspeed support
      usb: add USBBusOps->wakeup_endpoint
      usb: pass USBEndpoint to usb_wakeup
      usb: maintain async packet list per endpoint
      usb: Set USBEndpoint in usb_packet_setup().
      usb: add USBEndpoint->{nr,pid}
      usb: USBPacket: add status, rename owner -> ep
      usb: fold usb_generic_handle_packet into usb_handle_packet
      usb: kill handle_packet callback
      usb-xhci: switch to usb_find_device()
      usb-musb: switch to usb_find_device()
      usb-ohci: switch to usb_find_device()
      usb-ehci: switch to usb_find_device()
      usb-uhci: switch to usb_find_device()
      usb: handle dev == NULL in usb_handle_packet()
      ...

commit 65b31cc207b8ab949033870acf55bb124d12848e
Merge: b2d4b3f... b867672...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 15 17:18:04 2012 -0600

    Merge remote-tracking branch 'kwolf/for-anthony' into staging
    
    * kwolf/for-anthony:
      AHCI: Masking of IRQs actually masks them
      sheepdog: fix co_recv coroutine context
      AHCI: Fix port reset race
      rewrite QEMU_BUILD_BUG_ON
      qcow2: Keep unknown header extension when rewriting header
      qcow2: Update whole header at once
      vpc: Round up image size during fixed image creation
      vpc: Add support for Fixed Disk type
      iSCSI: add configuration variables for iSCSI
      qemu-io: add write -z option for bdrv_co_write_zeroes
      qed: add .bdrv_co_write_zeroes() support
      qed: replace is_write with flags field
      block: perform zero-detection during copy-on-read
      block: add .bdrv_co_write_zeroes() interface
      cutils: extract buffer_is_zero() from qemu-img.c

commit b2d4b3f7b8c8ad0519c4705a3b850446068e6946
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Sun Feb 12 11:36:24 2012 -0600

    device_add: don't add a /peripheral link until init is complete
    
    Otherwise we end up with a dangling reference which causes qdev_free() to fail.
    
    Reported-by: Michael Tsirkin <mst at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index 49f13ca..a310cc7 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -457,6 +457,16 @@ DeviceState *qdev_device_add(QemuOpts *opts)
     id = qemu_opts_id(opts);
     if (id) {
         qdev->id = id;
+    }
+    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;
+    }
+    if (qdev->id) {
         object_property_add_child(qdev_get_peripheral(), qdev->id,
                                   OBJECT(qdev), NULL);
     } else {
@@ -466,14 +476,6 @@ DeviceState *qdev_device_add(QemuOpts *opts)
                                   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;
 }
commit 83f7d43a9ef70b1b91e465173e18c845420e931e
Author: Andreas Färber <afaerber at suse.de>
Date:   Thu Feb 9 15:20:55 2012 +0100

    qom: Unify type registration
    
    Replace device_init() with generalized type_init().
    
    While at it, unify naming convention: type_init([$prefix_]register_types)
    Also, type_init() is a function, so add preceding blank line where
    necessary and don't put a semicolon after the closing brace.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Cc: Anthony Liguori <anthony at codemonkey.ws>
    Cc: malc <av1474 at comtv.ru>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 791a557..b8220ab 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -184,10 +184,10 @@ static TypeInfo virtio_9p_info = {
     .class_init    = virtio_9p_class_init,
 };
 
-static void virtio_9p_register_devices(void)
+static void virtio_9p_register_types(void)
 {
     type_register_static(&virtio_9p_info);
     virtio_9p_set_fd_limit();
 }
 
-device_init(virtio_9p_register_devices)
+type_init(virtio_9p_register_types)
diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index 19de12b..03b128c 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -238,9 +238,9 @@ static TypeInfo a9mp_priv_info = {
     .class_init    = a9mp_priv_class_init,
 };
 
-static void a9mp_register_devices(void)
+static void a9mp_register_types(void)
 {
     type_register_static(&a9mp_priv_info);
 }
 
-device_init(a9mp_register_devices)
+type_init(a9mp_register_types)
diff --git a/hw/ac97.c b/hw/ac97.c
index 7bf9171..c0fd019 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -1372,9 +1372,9 @@ static TypeInfo ac97_info = {
     .class_init    = ac97_class_init,
 };
 
-static void ac97_register (void)
+static void ac97_register_types (void)
 {
     type_register_static (&ac97_info);
 }
-device_init (ac97_register);
 
+type_init (ac97_register_types)
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 21484ae..d959f49 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -426,12 +426,12 @@ static TypeInfo piix4_pm_info = {
     .class_init    = piix4_pm_class_init,
 };
 
-static void piix4_pm_register(void)
+static void piix4_pm_register_types(void)
 {
     type_register_static(&piix4_pm_info);
 }
 
-device_init(piix4_pm_register);
+type_init(piix4_pm_register_types)
 
 static uint32_t gpe_readb(void *opaque, uint32_t addr)
 {
diff --git a/hw/ads7846.c b/hw/ads7846.c
index 3cfdecb..41c7f10 100644
--- a/hw/ads7846.c
+++ b/hw/ads7846.c
@@ -168,9 +168,9 @@ static TypeInfo ads7846_info = {
     .class_init    = ads7846_class_init,
 };
 
-static void ads7846_register_devices(void)
+static void ads7846_register_types(void)
 {
     type_register_static(&ads7846_info);
 }
 
-device_init(ads7846_register_devices)
+type_init(ads7846_register_types)
diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c
index 736c28a..b539416 100644
--- a/hw/alpha_typhoon.c
+++ b/hw/alpha_typhoon.c
@@ -824,8 +824,9 @@ static TypeInfo typhoon_pcihost_info = {
     .class_init    = typhoon_pcihost_class_init,
 };
 
-static void typhoon_register(void)
+static void typhoon_register_types(void)
 {
     type_register_static(&typhoon_pcihost_info);
 }
-device_init(typhoon_register);
+
+type_init(typhoon_register_types)
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index c7aaa72..1d25da8 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -493,11 +493,11 @@ static TypeInfo pbm_pci_bridge_info = {
     .class_init    = pbm_pci_bridge_class_init,
 };
 
-static void pbm_register_devices(void)
+static void pbm_register_types(void)
 {
     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)
+type_init(pbm_register_types)
diff --git a/hw/apic.c b/hw/apic.c
index 086c544..ff9d24e 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -781,9 +781,9 @@ static TypeInfo apic_info = {
     .class_init    = apic_class_init,
 };
 
-static void apic_register_devices(void)
+static void apic_register_types(void)
 {
     type_register_static(&apic_info);
 }
 
-device_init(apic_register_devices)
+type_init(apic_register_types)
diff --git a/hw/apic_common.c b/hw/apic_common.c
index 26991b4..a440ea8 100644
--- a/hw/apic_common.c
+++ b/hw/apic_common.c
@@ -313,9 +313,9 @@ static TypeInfo apic_common_type = {
     .abstract = true,
 };
 
-static void register_devices(void)
+static void register_types(void)
 {
     type_register_static(&apic_common_type);
 }
 
-device_init(register_devices);
+type_init(register_types)
diff --git a/hw/applesmc.c b/hw/applesmc.c
index b06487f..8bedaad 100644
--- a/hw/applesmc.c
+++ b/hw/applesmc.c
@@ -243,9 +243,9 @@ static TypeInfo applesmc_isa_info = {
     .class_init    = qdev_applesmc_class_init,
 };
 
-static void applesmc_register_devices(void)
+static void applesmc_register_types(void)
 {
     type_register_static(&applesmc_isa_info);
 }
 
-device_init(applesmc_register_devices)
+type_init(applesmc_register_types)
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index 3c0839c..102348b 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -252,10 +252,10 @@ static TypeInfo mpcore_priv_info = {
     .class_init    = mpcore_priv_class_init,
 };
 
-static void arm11mpcore_register_devices(void)
+static void arm11mpcore_register_types(void)
 {
     type_register_static(&mpcore_rirq_info);
     type_register_static(&mpcore_priv_info);
 }
 
-device_init(arm11mpcore_register_devices)
+type_init(arm11mpcore_register_types)
diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c
index ba26abc..09f290c 100644
--- a/hw/arm_l2x0.c
+++ b/hw/arm_l2x0.c
@@ -184,9 +184,9 @@ static TypeInfo l2x0_info = {
     .class_init = l2x0_class_init,
 };
 
-static void l2x0_register_device(void)
+static void l2x0_register_types(void)
 {
     type_register_static(&l2x0_info);
 }
 
-device_init(l2x0_register_device)
+type_init(l2x0_register_types)
diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c
index 5a02365..361e887 100644
--- a/hw/arm_mptimer.c
+++ b/hw/arm_mptimer.c
@@ -335,9 +335,9 @@ static TypeInfo arm_mptimer_info = {
     .class_init    = arm_mptimer_class_init,
 };
 
-static void arm_mptimer_register_devices(void)
+static void arm_mptimer_register_types(void)
 {
     type_register_static(&arm_mptimer_info);
 }
 
-device_init(arm_mptimer_register_devices)
+type_init(arm_mptimer_register_types)
diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index 9d25799..149c639 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -425,9 +425,9 @@ static TypeInfo arm_sysctl_info = {
     .class_init    = arm_sysctl_class_init,
 };
 
-static void arm_sysctl_register_devices(void)
+static void arm_sysctl_register_types(void)
 {
     type_register_static(&arm_sysctl_info);
 }
 
-device_init(arm_sysctl_register_devices)
+type_init(arm_sysctl_register_types)
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 1019d41..e3ecce2 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -383,10 +383,10 @@ static TypeInfo sp804_info = {
     .class_init    = sp804_class_init,
 };
 
-static void arm_timer_register_devices(void)
+static void arm_timer_register_types(void)
 {
     type_register_static(&icp_pit_info);
     type_register_static(&sp804_info);
 }
 
-device_init(arm_timer_register_devices)
+type_init(arm_timer_register_types)
diff --git a/hw/armv7m.c b/hw/armv7m.c
index de3d7e0..6b80579 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -266,9 +266,9 @@ static TypeInfo bitband_info = {
     .class_init    = bitband_class_init,
 };
 
-static void armv7m_register_devices(void)
+static void armv7m_register_types(void)
 {
     type_register_static(&bitband_info);
 }
 
-device_init(armv7m_register_devices)
+type_init(armv7m_register_types)
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index 1ed0abc..3210129 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -417,9 +417,9 @@ static TypeInfo armv7m_nvic_info = {
     .class_init    = armv7m_nvic_class_init,
 };
 
-static void armv7m_nvic_register_devices(void)
+static void armv7m_nvic_register_types(void)
 {
     type_register_static(&armv7m_nvic_info);
 }
 
-device_init(armv7m_nvic_register_devices)
+type_init(armv7m_nvic_register_types)
diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c
index c9c1182..44ed7f4 100644
--- a/hw/bitbang_i2c.c
+++ b/hw/bitbang_i2c.c
@@ -237,9 +237,9 @@ static TypeInfo gpio_i2c_info = {
     .class_init    = gpio_i2c_class_init,
 };
 
-static void bitbang_i2c_register(void)
+static void bitbang_i2c_register_types(void)
 {
     type_register_static(&gpio_i2c_info);
 }
 
-device_init(bitbang_i2c_register)
+type_init(bitbang_i2c_register_types)
diff --git a/hw/bonito.c b/hw/bonito.c
index 7350a4f..77786f8 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -804,9 +804,10 @@ static TypeInfo bonito_pcihost_info = {
     .class_init    = bonito_pcihost_class_init,
 };
 
-static void bonito_register(void)
+static void bonito_register_types(void)
 {
     type_register_static(&bonito_pcihost_info);
     type_register_static(&bonito_info);
 }
-device_init(bonito_register);
+
+type_init(bonito_register_types)
diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c
index 9510ed4..f4a6da4 100644
--- a/hw/ccid-card-emulated.c
+++ b/hw/ccid-card-emulated.c
@@ -594,9 +594,9 @@ static TypeInfo emulated_card_info = {
     .class_init    = emulated_class_initfn,
 };
 
-static void ccid_card_emulated_register_devices(void)
+static void ccid_card_emulated_register_types(void)
 {
     type_register_static(&emulated_card_info);
 }
 
-device_init(ccid_card_emulated_register_devices)
+type_init(ccid_card_emulated_register_types)
diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c
index a7006ca..bd6c777 100644
--- a/hw/ccid-card-passthru.c
+++ b/hw/ccid-card-passthru.c
@@ -343,9 +343,9 @@ static TypeInfo passthru_card_info = {
     .class_init    = passthru_class_initfn,
 };
 
-static void ccid_card_passthru_register_devices(void)
+static void ccid_card_passthru_register_types(void)
 {
     type_register_static(&passthru_card_info);
 }
 
-device_init(ccid_card_passthru_register_devices)
+type_init(ccid_card_passthru_register_types)
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index a8e8ab7..4edcb94 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2923,12 +2923,6 @@ static TypeInfo isa_cirrus_vga_info = {
     .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
@@ -2996,8 +2990,10 @@ static TypeInfo cirrus_vga_info = {
     .class_init    = cirrus_vga_class_init,
 };
 
-static void cirrus_vga_register(void)
+static void cirrus_vga_register_types(void)
 {
+    type_register_static(&isa_cirrus_vga_info);
     type_register_static(&cirrus_vga_info);
 }
-device_init(cirrus_vga_register);
+
+type_init(cirrus_vga_register_types)
diff --git a/hw/cs4231.c b/hw/cs4231.c
index c0badbf..cfec1d9 100644
--- a/hw/cs4231.c
+++ b/hw/cs4231.c
@@ -173,9 +173,9 @@ static TypeInfo cs4231_info = {
     .class_init    = cs4231_class_init,
 };
 
-static void cs4231_register_devices(void)
+static void cs4231_register_types(void)
 {
     type_register_static(&cs4231_info);
 }
 
-device_init(cs4231_register_devices)
+type_init(cs4231_register_types)
diff --git a/hw/cs4231a.c b/hw/cs4231a.c
index ad04ad6..e07b9d6 100644
--- a/hw/cs4231a.c
+++ b/hw/cs4231a.c
@@ -689,8 +689,9 @@ static TypeInfo cs4231a_info = {
     .class_init    = cs4231a_class_initfn,
 };
 
-static void cs4231a_register (void)
+static void cs4231a_register_types (void)
 {
     type_register_static (&cs4231a_info);
 }
-device_init (cs4231a_register)
+
+type_init (cs4231a_register_types)
diff --git a/hw/debugcon.c b/hw/debugcon.c
index 3903b26..14ab326 100644
--- a/hw/debugcon.c
+++ b/hw/debugcon.c
@@ -109,9 +109,9 @@ static TypeInfo debugcon_isa_info = {
     .class_init    = debugcon_isa_class_initfn,
 };
 
-static void debugcon_register_devices(void)
+static void debugcon_register_types(void)
 {
     type_register_static(&debugcon_isa_info);
 }
 
-device_init(debugcon_register_devices)
+type_init(debugcon_register_types)
diff --git a/hw/dec_pci.c b/hw/dec_pci.c
index a40fbcf..37337bf 100644
--- a/hw/dec_pci.c
+++ b/hw/dec_pci.c
@@ -140,11 +140,11 @@ static TypeInfo pci_dec_21154_device_info = {
     .class_init    = pci_dec_21154_device_class_init,
 };
 
-static void dec_register_devices(void)
+static void dec_register_types(void)
 {
     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)
+type_init(dec_register_types)
diff --git a/hw/ds1225y.c b/hw/ds1225y.c
index 539bceb..2cd355b 100644
--- a/hw/ds1225y.c
+++ b/hw/ds1225y.c
@@ -157,9 +157,9 @@ static TypeInfo nvram_sysbus_info = {
     .class_init    = nvram_sysbus_class_init,
 };
 
-static void nvram_register(void)
+static void nvram_register_types(void)
 {
     type_register_static(&nvram_sysbus_info);
 }
 
-device_init(nvram_register)
+type_init(nvram_register_types)
diff --git a/hw/ds1338.c b/hw/ds1338.c
index b137e13..6397f0a 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -135,9 +135,9 @@ static TypeInfo ds1338_info = {
     .class_init    = ds1338_class_init,
 };
 
-static void ds1338_register_devices(void)
+static void ds1338_register_types(void)
 {
     type_register_static(&ds1338_info);
 }
 
-device_init(ds1338_register_devices)
+type_init(ds1338_register_types)
diff --git a/hw/e1000.c b/hw/e1000.c
index 751f79d..7babc0b 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -1227,9 +1227,9 @@ static TypeInfo e1000_info = {
     .class_init    = e1000_class_init,
 };
 
-static void e1000_register_devices(void)
+static void e1000_register_types(void)
 {
     type_register_static(&e1000_info);
 }
 
-device_init(e1000_register_devices)
+type_init(e1000_register_types)
diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c
index 1cf2090..fe1cd90 100644
--- a/hw/eccmemctl.c
+++ b/hw/eccmemctl.c
@@ -332,9 +332,9 @@ static TypeInfo ecc_info = {
 };
 
 
-static void ecc_register_devices(void)
+static void ecc_register_types(void)
 {
     type_register_static(&ecc_info);
 }
 
-device_init(ecc_register_devices)
+type_init(ecc_register_types)
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 843610c..e3ba719 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -2089,7 +2089,7 @@ static void eepro100_class_init(ObjectClass *klass, void *data)
     k->subsystem_id = info->subsystem_id;
 }
 
-static void eepro100_register_devices(void)
+static void eepro100_register_types(void)
 {
     size_t i;
     for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
@@ -2105,4 +2105,4 @@ static void eepro100_register_devices(void)
     }
 }
 
-device_init(eepro100_register_devices)
+type_init(eepro100_register_types)
diff --git a/hw/empty_slot.c b/hw/empty_slot.c
index 1bc1815..099c85e 100644
--- a/hw/empty_slot.c
+++ b/hw/empty_slot.c
@@ -90,9 +90,9 @@ static TypeInfo empty_slot_info = {
     .class_init    = empty_slot_class_init,
 };
 
-static void empty_slot_register_devices(void)
+static void empty_slot_register_types(void)
 {
     type_register_static(&empty_slot_info);
 }
 
-device_init(empty_slot_register_devices);
+type_init(empty_slot_register_types)
diff --git a/hw/es1370.c b/hw/es1370.c
index e377c48..f19cef3 100644
--- a/hw/es1370.c
+++ b/hw/es1370.c
@@ -1054,9 +1054,10 @@ static TypeInfo es1370_info = {
     .class_init    = es1370_class_init,
 };
 
-static void es1370_register (void)
+static void es1370_register_types (void)
 {
     type_register_static (&es1370_info);
 }
-device_init (es1370_register);
+
+type_init (es1370_register_types)
 
diff --git a/hw/escc.c b/hw/escc.c
index 9fe282f..4d8a8e8 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -931,9 +931,9 @@ static TypeInfo escc_info = {
     .class_init    = escc_class_init,
 };
 
-static void escc_register_devices(void)
+static void escc_register_types(void)
 {
     type_register_static(&escc_info);
 }
 
-device_init(escc_register_devices)
+type_init(escc_register_types)
diff --git a/hw/esp.c b/hw/esp.c
index 2f44386..2dda8e3 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -775,9 +775,9 @@ static TypeInfo esp_info = {
     .class_init    = esp_class_init,
 };
 
-static void esp_register_devices(void)
+static void esp_register_types(void)
 {
     type_register_static(&esp_info);
 }
 
-device_init(esp_register_devices)
+type_init(esp_register_types)
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index aefd577..16a0637 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -637,9 +637,9 @@ static TypeInfo etraxfs_eth_info = {
     .class_init    = etraxfs_eth_class_init,
 };
 
-static void etraxfs_eth_register(void)
+static void etraxfs_eth_register_types(void)
 {
     type_register_static(&etraxfs_eth_info);
 }
 
-device_init(etraxfs_eth_register)
+type_init(etraxfs_eth_register_types)
diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c
index 33541fc..dc27f88 100644
--- a/hw/etraxfs_pic.c
+++ b/hw/etraxfs_pic.c
@@ -172,9 +172,9 @@ static TypeInfo etraxfs_pic_info = {
     .class_init    = etraxfs_pic_class_init,
 };
 
-static void etraxfs_pic_register(void)
+static void etraxfs_pic_register_types(void)
 {
     type_register_static(&etraxfs_pic_info);
 }
 
-device_init(etraxfs_pic_register)
+type_init(etraxfs_pic_register_types)
diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c
index 567cb8c..cecd819 100644
--- a/hw/etraxfs_ser.c
+++ b/hw/etraxfs_ser.c
@@ -240,9 +240,9 @@ static TypeInfo etraxfs_ser_info = {
     .class_init    = etraxfs_ser_class_init,
 };
 
-static void etraxfs_serial_register(void)
+static void etraxfs_serial_register_types(void)
 {
     type_register_static(&etraxfs_ser_info);
 }
 
-device_init(etraxfs_serial_register)
+type_init(etraxfs_serial_register_types)
diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
index b71c5ee..9076a49 100644
--- a/hw/etraxfs_timer.c
+++ b/hw/etraxfs_timer.c
@@ -343,9 +343,9 @@ static TypeInfo etraxfs_timer_info = {
     .class_init    = etraxfs_timer_class_init,
 };
 
-static void etraxfs_timer_register(void)
+static void etraxfs_timer_register_types(void)
 {
     type_register_static(&etraxfs_timer_info);
 }
 
-device_init(etraxfs_timer_register)
+type_init(etraxfs_timer_register_types)
diff --git a/hw/fdc.c b/hw/fdc.c
index f575a2c..38fad58 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -2043,11 +2043,11 @@ static TypeInfo sun4m_fdc_info = {
     .class_init    = sun4m_fdc_class_init,
 };
 
-static void fdc_register_devices(void)
+static void fdc_register_types(void)
 {
     type_register_static(&isa_fdc_info);
     type_register_static(&sysbus_fdc_info);
     type_register_static(&sun4m_fdc_info);
 }
 
-device_init(fdc_register_devices)
+type_init(fdc_register_types)
diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c
index 6b2f7d1..7b3b576 100644
--- a/hw/fw_cfg.c
+++ b/hw/fw_cfg.c
@@ -556,9 +556,9 @@ static TypeInfo fw_cfg_info = {
     .class_init    = fw_cfg_class_init,
 };
 
-static void fw_cfg_register_devices(void)
+static void fw_cfg_register_types(void)
 {
     type_register_static(&fw_cfg_info);
 }
 
-device_init(fw_cfg_register_devices)
+type_init(fw_cfg_register_types)
diff --git a/hw/g364fb.c b/hw/g364fb.c
index 66d0044..9c63bdd 100644
--- a/hw/g364fb.c
+++ b/hw/g364fb.c
@@ -574,9 +574,9 @@ static TypeInfo g364fb_sysbus_info = {
     .class_init    = g364fb_sysbus_class_init,
 };
 
-static void g364fb_register(void)
+static void g364fb_register_types(void)
 {
     type_register_static(&g364fb_sysbus_info);
 }
 
-device_init(g364fb_register);
+type_init(g364fb_register_types)
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index 8122baf..81ff3a3 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -157,10 +157,10 @@ static TypeInfo grackle_pci_host_info = {
     .class_init    = pci_grackle_class_init,
 };
 
-static void grackle_register_devices(void)
+static void grackle_register_types(void)
 {
     type_register_static(&grackle_pci_info);
     type_register_static(&grackle_pci_host_info);
 }
 
-device_init(grackle_register_devices)
+type_init(grackle_register_types)
diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
index 89de2d8..73fc989 100644
--- a/hw/grlib_apbuart.c
+++ b/hw/grlib_apbuart.c
@@ -263,9 +263,9 @@ static TypeInfo grlib_gptimer_info = {
     .class_init    = grlib_gptimer_class_init,
 };
 
-static void grlib_gptimer_register(void)
+static void grlib_gptimer_register_types(void)
 {
     type_register_static(&grlib_gptimer_info);
 }
 
-device_init(grlib_gptimer_register)
+type_init(grlib_gptimer_register_types)
diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c
index fb0b236..41770a9 100644
--- a/hw/grlib_gptimer.c
+++ b/hw/grlib_gptimer.c
@@ -396,9 +396,9 @@ static TypeInfo grlib_gptimer_info = {
     .class_init    = grlib_gptimer_class_init,
 };
 
-static void grlib_gptimer_register(void)
+static void grlib_gptimer_register_types(void)
 {
     type_register_static(&grlib_gptimer_info);
 }
 
-device_init(grlib_gptimer_register)
+type_init(grlib_gptimer_register_types)
diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c
index 1e5ad82..0f6e65c 100644
--- a/hw/grlib_irqmp.c
+++ b/hw/grlib_irqmp.c
@@ -377,9 +377,9 @@ static TypeInfo grlib_irqmp_info = {
     .class_init    = grlib_irqmp_class_init,
 };
 
-static void grlib_irqmp_register(void)
+static void grlib_irqmp_register_types(void)
 {
     type_register_static(&grlib_irqmp_info);
 }
 
-device_init(grlib_irqmp_register)
+type_init(grlib_irqmp_register_types)
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index e8cd59c..a2d0e5a 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -1168,10 +1168,10 @@ static TypeInfo gt64120_info = {
     .class_init    = gt64120_class_init,
 };
 
-static void gt64120_pci_register_devices(void)
+static void gt64120_pci_register_types(void)
 {
     type_register_static(&gt64120_info);
     type_register_static(&gt64120_pci_info);
 }
 
-device_init(gt64120_pci_register_devices)
+type_init(gt64120_pci_register_types)
diff --git a/hw/gus.c b/hw/gus.c
index 2054707..840d098 100644
--- a/hw/gus.c
+++ b/hw/gus.c
@@ -324,8 +324,9 @@ static TypeInfo gus_info = {
     .class_init    = gus_class_initfn,
 };
 
-static void gus_register (void)
+static void gus_register_types (void)
 {
     type_register_static (&gus_info);
 }
-device_init (gus_register)
+
+type_init (gus_register_types)
diff --git a/hw/hda-audio.c b/hw/hda-audio.c
index 152f8e6..8995519 100644
--- a/hw/hda-audio.c
+++ b/hw/hda-audio.c
@@ -948,9 +948,10 @@ static TypeInfo hda_audio_duplex_info = {
     .class_init    = hda_audio_duplex_class_init,
 };
 
-static void hda_audio_register(void)
+static void hda_audio_register_types(void)
 {
     type_register_static(&hda_audio_output_info);
     type_register_static(&hda_audio_duplex_info);
 }
-device_init(hda_audio_register);
+
+type_init(hda_audio_register_types)
diff --git a/hw/highbank.c b/hw/highbank.c
index 684178e..b28b464 100644
--- a/hw/highbank.c
+++ b/hw/highbank.c
@@ -177,12 +177,12 @@ static TypeInfo highbank_regs_info = {
     .class_init    = highbank_regs_class_init,
 };
 
-static void highbank_regs_register_device(void)
+static void highbank_regs_register_types(void)
 {
     type_register_static(&highbank_regs_info);
 }
 
-device_init(highbank_regs_register_device)
+type_init(highbank_regs_register_types)
 
 static struct arm_boot_info highbank_binfo;
 
diff --git a/hw/hpet.c b/hw/hpet.c
index b6ace4e..ba36e10 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -720,9 +720,9 @@ static TypeInfo hpet_device_info = {
     .class_init    = hpet_device_class_init,
 };
 
-static void hpet_register_device(void)
+static void hpet_register_types(void)
 {
     type_register_static(&hpet_device_info);
 }
 
-device_init(hpet_register_device)
+type_init(hpet_register_types)
diff --git a/hw/i2c.c b/hw/i2c.c
index 8ae4aaa..23dfccb 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -230,9 +230,9 @@ static TypeInfo i2c_slave_type_info = {
     .class_init = i2c_slave_class_init,
 };
 
-static void i2c_slave_register_devices(void)
+static void i2c_slave_register_types(void)
 {
     type_register_static(&i2c_slave_type_info);
 }
 
-device_init(i2c_slave_register_devices);
+type_init(i2c_slave_register_types)
diff --git a/hw/i82374.c b/hw/i82374.c
index 220e8cc..67298a3 100644
--- a/hw/i82374.c
+++ b/hw/i82374.c
@@ -157,9 +157,9 @@ static TypeInfo i82374_isa_info = {
     .class_init = i82374_class_init,
 };
 
-static void i82374_register_devices(void)
+static void i82374_register_types(void)
 {
     type_register_static(&i82374_isa_info);
 }
 
-device_init(i82374_register_devices)
+type_init(i82374_register_types)
diff --git a/hw/i82378.c b/hw/i82378.c
index 9c3efe8..3929c04 100644
--- a/hw/i82378.c
+++ b/hw/i82378.c
@@ -267,9 +267,9 @@ static TypeInfo pci_i82378_info = {
     .class_init = pci_i82378_class_init,
 };
 
-static void i82378_register_devices(void)
+static void i82378_register_types(void)
 {
     type_register_static(&pci_i82378_info);
 }
 
-device_init(i82378_register_devices)
+type_init(i82378_register_types)
diff --git a/hw/i8254.c b/hw/i8254.c
index 522fed8..481fc7b 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -559,8 +559,9 @@ static TypeInfo pit_info = {
     .class_init    = pit_class_initfn,
 };
 
-static void pit_register(void)
+static void pit_register_types(void)
 {
     type_register_static(&pit_info);
 }
-device_init(pit_register)
+
+type_init(pit_register_types)
diff --git a/hw/i8259.c b/hw/i8259.c
index 7ae5380..1a4b1ab 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -488,9 +488,9 @@ static TypeInfo i8259_info = {
     .class_init = i8259_class_init,
 };
 
-static void pic_register(void)
+static void pic_register_types(void)
 {
     type_register_static(&i8259_info);
 }
 
-device_init(pic_register)
+type_init(pic_register_types)
diff --git a/hw/i8259_common.c b/hw/i8259_common.c
index 9f150bc..775fda4 100644
--- a/hw/i8259_common.c
+++ b/hw/i8259_common.c
@@ -153,9 +153,9 @@ static TypeInfo pic_common_type = {
     .abstract = true,
 };
 
-static void register_devices(void)
+static void register_types(void)
 {
     type_register_static(&pic_common_type);
 }
 
-device_init(register_devices);
+type_init(register_types);
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index c87a6ca..c360399 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -1261,9 +1261,9 @@ static TypeInfo sysbus_ahci_info = {
     .class_init    = sysbus_ahci_class_init,
 };
 
-static void sysbus_ahci_register(void)
+static void sysbus_ahci_register_types(void)
 {
     type_register_static(&sysbus_ahci_info);
 }
 
-device_init(sysbus_ahci_register);
+type_init(sysbus_ahci_register_types)
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index a119500..743ec02 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -351,8 +351,9 @@ static TypeInfo cmd646_ide_info = {
     .class_init    = cmd646_ide_class_init,
 };
 
-static void cmd646_ide_register(void)
+static void cmd646_ide_register_types(void)
 {
     type_register_static(&cmd646_ide_info);
 }
-device_init(cmd646_ide_register);
+
+type_init(cmd646_ide_register_types)
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 5cdaa99..560ae37 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -168,8 +168,9 @@ static TypeInfo ich_ahci_info = {
     .class_init    = ich_ahci_class_init,
 };
 
-static void ich_ahci_register(void)
+static void ich_ahci_register_types(void)
 {
     type_register_static(&ich_ahci_info);
 }
-device_init(ich_ahci_register);
+
+type_init(ich_ahci_register_types)
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index a0bcb43..8ab2718 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -118,9 +118,9 @@ static TypeInfo isa_ide_info = {
     .class_init    = isa_ide_class_initfn,
 };
 
-static void isa_ide_register_devices(void)
+static void isa_ide_register_types(void)
 {
     type_register_static(&isa_ide_info);
 }
 
-device_init(isa_ide_register_devices)
+type_init(isa_ide_register_types)
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index bf4465b..aee60aa 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -299,10 +299,11 @@ static TypeInfo piix4_ide_info = {
     .class_init    = piix4_ide_class_init,
 };
 
-static void piix_ide_register(void)
+static void piix_ide_register_types(void)
 {
     type_register_static(&piix3_ide_info);
     type_register_static(&piix3_ide_xen_info);
     type_register_static(&piix4_ide_info);
 }
-device_init(piix_ide_register);
+
+type_init(piix_ide_register_types)
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 1640616..f6a4896 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -257,11 +257,12 @@ static TypeInfo ide_device_type_info = {
     .class_init = ide_device_class_init,
 };
 
-static void ide_dev_register(void)
+static void ide_register_types(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);
+
+type_init(ide_register_types)
diff --git a/hw/ide/via.c b/hw/ide/via.c
index b4ca6f2..2886bc6 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -234,8 +234,9 @@ static TypeInfo via_ide_info = {
     .class_init    = via_ide_class_init,
 };
 
-static void via_ide_register(void)
+static void via_ide_register_types(void)
 {
     type_register_static(&via_ide_info);
 }
-device_init(via_ide_register);
+
+type_init(via_ide_register_types)
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index 6dbd649..294d7da 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -553,10 +553,10 @@ static TypeInfo icp_pic_info = {
     .class_init    = icp_pic_class_init,
 };
 
-static void integratorcp_register_devices(void)
+static void integratorcp_register_types(void)
 {
     type_register_static(&icp_pic_info);
     type_register_static(&core_info);
 }
 
-device_init(integratorcp_register_devices)
+type_init(integratorcp_register_types)
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 83c42d5..bb11af2 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -1287,12 +1287,13 @@ static TypeInfo hda_codec_device_type_info = {
     .class_init = hda_codec_device_class_init,
 };
 
-static void intel_hda_register(void)
+static void intel_hda_register_types(void)
 {
     type_register_static(&intel_hda_info);
     type_register_static(&hda_codec_device_type_info);
 }
-device_init(intel_hda_register);
+
+type_init(intel_hda_register_types)
 
 /*
  * create intel hda controller with codec attached to it,
diff --git a/hw/ioapic.c b/hw/ioapic.c
index 79549f8..3fee011 100644
--- a/hw/ioapic.c
+++ b/hw/ioapic.c
@@ -251,9 +251,9 @@ static TypeInfo ioapic_info = {
     .class_init    = ioapic_class_init,
 };
 
-static void ioapic_register_devices(void)
+static void ioapic_register_types(void)
 {
     type_register_static(&ioapic_info);
 }
 
-device_init(ioapic_register_devices)
+type_init(ioapic_register_types)
diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c
index f932700..653eef2 100644
--- a/hw/ioapic_common.c
+++ b/hw/ioapic_common.c
@@ -112,10 +112,9 @@ static TypeInfo ioapic_common_type = {
     .abstract = true,
 };
 
-static void register_devices(void)
+static void register_types(void)
 {
     type_register_static(&ioapic_common_type);
 }
 
-device_init(register_devices);
-
+type_init(register_types)
diff --git a/hw/ioh3420.c b/hw/ioh3420.c
index 1c60123..1632d31 100644
--- a/hw/ioh3420.c
+++ b/hw/ioh3420.c
@@ -237,12 +237,12 @@ static TypeInfo ioh3420_info = {
     .class_init    = ioh3420_class_init,
 };
 
-static void ioh3420_register(void)
+static void ioh3420_register_types(void)
 {
     type_register_static(&ioh3420_info);
 }
 
-device_init(ioh3420_register);
+type_init(ioh3420_register_types)
 
 /*
  * Local variables:
diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index d03f828..5a43f03 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -210,7 +210,7 @@ static TypeInfo isa_device_type_info = {
     .class_init = isa_device_class_init,
 };
 
-static void isabus_register_devices(void)
+static void isabus_register_types(void)
 {
     type_register_static(&isabus_bridge_info);
     type_register_static(&isa_device_type_info);
@@ -235,4 +235,4 @@ MemoryRegion *isa_address_space(ISADevice *dev)
     return get_system_memory();
 }
 
-device_init(isabus_register_devices)
+type_init(isabus_register_types)
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index 6f017d4..64e1cd9 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -798,9 +798,9 @@ static TypeInfo ivshmem_info = {
     .class_init    = ivshmem_class_init,
 };
 
-static void ivshmem_register_devices(void)
+static void ivshmem_register_types(void)
 {
     type_register_static(&ivshmem_info);
 }
 
-device_init(ivshmem_register_devices)
+type_init(ivshmem_register_types)
diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c
index dfc2ab3..5bb0a4b 100644
--- a/hw/kvm/apic.c
+++ b/hw/kvm/apic.c
@@ -139,9 +139,9 @@ static TypeInfo kvm_apic_info = {
     .class_init = kvm_apic_class_init,
 };
 
-static void kvm_apic_register_device(void)
+static void kvm_apic_register_types(void)
 {
     type_register_static(&kvm_apic_info);
 }
 
-device_init(kvm_apic_register_device)
+type_init(kvm_apic_register_types)
diff --git a/hw/kvm/clock.c b/hw/kvm/clock.c
index d5a5386..2157340 100644
--- a/hw/kvm/clock.c
+++ b/hw/kvm/clock.c
@@ -119,11 +119,11 @@ void kvmclock_create(void)
     }
 }
 
-static void kvmclock_register_device(void)
+static void kvmclock_register_types(void)
 {
     if (kvm_enabled()) {
     type_register_static(&kvmclock_info);
     }
 }
 
-device_init(kvmclock_register_device);
+type_init(kvmclock_register_types)
diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c
index 14bd427..eb98889 100644
--- a/hw/kvm/i8259.c
+++ b/hw/kvm/i8259.c
@@ -130,9 +130,9 @@ static TypeInfo kvm_i8259_info = {
     .class_init = kvm_i8259_class_init,
 };
 
-static void kvm_pic_register(void)
+static void kvm_pic_register_types(void)
 {
     type_register_static(&kvm_i8259_info);
 }
 
-device_init(kvm_pic_register)
+type_init(kvm_pic_register_types)
diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c
index b316933..3ae3175 100644
--- a/hw/kvm/ioapic.c
+++ b/hw/kvm/ioapic.c
@@ -117,9 +117,9 @@ static TypeInfo kvm_ioapic_info = {
     .class_init = kvm_ioapic_class_init,
 };
 
-static void kvm_ioapic_register_device(void)
+static void kvm_ioapic_register_types(void)
 {
     type_register_static(&kvm_ioapic_info);
 }
 
-device_init(kvm_ioapic_register_device)
+type_init(kvm_ioapic_register_types)
diff --git a/hw/lan9118.c b/hw/lan9118.c
index 78777c7..aeb0c39 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -1261,7 +1261,7 @@ static TypeInfo lan9118_info = {
     .class_init    = lan9118_class_init,
 };
 
-static void lan9118_register_devices(void)
+static void lan9118_register_types(void)
 {
     type_register_static(&lan9118_info);
 }
@@ -1282,4 +1282,4 @@ void lan9118_init(NICInfo *nd, uint32_t base, qemu_irq irq)
     sysbus_connect_irq(s, 0, irq);
 }
 
-device_init(lan9118_register_devices)
+type_init(lan9118_register_types)
diff --git a/hw/lance.c b/hw/lance.c
index 519720b..ce3d46c 100644
--- a/hw/lance.c
+++ b/hw/lance.c
@@ -162,8 +162,9 @@ static TypeInfo lance_info = {
     .class_init    = lance_class_init,
 };
 
-static void lance_register_devices(void)
+static void lance_register_types(void)
 {
     type_register_static(&lance_info);
 }
-device_init(lance_register_devices)
+
+type_init(lance_register_types)
diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c
index 38dd282..f07ed39 100644
--- a/hw/lm32_juart.c
+++ b/hw/lm32_juart.c
@@ -151,9 +151,9 @@ static TypeInfo lm32_juart_info = {
     .class_init    = lm32_juart_class_init,
 };
 
-static void lm32_juart_register(void)
+static void lm32_juart_register_types(void)
 {
     type_register_static(&lm32_juart_info);
 }
 
-device_init(lm32_juart_register)
+type_init(lm32_juart_register_types)
diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c
index 7be6d0d..32f65db 100644
--- a/hw/lm32_pic.c
+++ b/hw/lm32_pic.c
@@ -191,9 +191,9 @@ static TypeInfo lm32_pic_info = {
     .class_init    = lm32_pic_class_init,
 };
 
-static void lm32_pic_register(void)
+static void lm32_pic_register_types(void)
 {
     type_register_static(&lm32_pic_info);
 }
 
-device_init(lm32_pic_register)
+type_init(lm32_pic_register_types)
diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c
index ba6f4ac..bbe03c4 100644
--- a/hw/lm32_sys.c
+++ b/hw/lm32_sys.c
@@ -164,9 +164,9 @@ static TypeInfo lm32_sys_info = {
     .class_init    = lm32_sys_class_init,
 };
 
-static void lm32_sys_register(void)
+static void lm32_sys_register_types(void)
 {
     type_register_static(&lm32_sys_info);
 }
 
-device_init(lm32_sys_register)
+type_init(lm32_sys_register_types)
diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c
index 3cb4e0a..e9450a0 100644
--- a/hw/lm32_timer.c
+++ b/hw/lm32_timer.c
@@ -222,9 +222,9 @@ static TypeInfo lm32_timer_info = {
     .class_init    = lm32_timer_class_init,
 };
 
-static void lm32_timer_register(void)
+static void lm32_timer_register_types(void)
 {
     type_register_static(&lm32_timer_info);
 }
 
-device_init(lm32_timer_register)
+type_init(lm32_timer_register_types)
diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c
index 630ccb7..57066e2 100644
--- a/hw/lm32_uart.c
+++ b/hw/lm32_uart.c
@@ -288,9 +288,9 @@ static TypeInfo lm32_uart_info = {
     .class_init    = lm32_uart_class_init,
 };
 
-static void lm32_uart_register(void)
+static void lm32_uart_register_types(void)
 {
     type_register_static(&lm32_uart_info);
 }
 
-device_init(lm32_uart_register)
+type_init(lm32_uart_register_types)
diff --git a/hw/lm832x.c b/hw/lm832x.c
index 895d306..8e09f9b 100644
--- a/hw/lm832x.c
+++ b/hw/lm832x.c
@@ -513,9 +513,9 @@ static TypeInfo lm8323_info = {
     .class_init    = lm8323_class_init,
 };
 
-static void lm832x_register_devices(void)
+static void lm832x_register_types(void)
 {
     type_register_static(&lm8323_info);
 }
 
-device_init(lm832x_register_devices)
+type_init(lm832x_register_types)
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 9a7ffe3..0acd1d0 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -2142,9 +2142,9 @@ static TypeInfo lsi_info = {
     .class_init    = lsi_class_init,
 };
 
-static void lsi53c895a_register_devices(void)
+static void lsi53c895a_register_types(void)
 {
     type_register_static(&lsi_info);
 }
 
-device_init(lsi53c895a_register_devices);
+type_init(lsi53c895a_register_types)
diff --git a/hw/m48t59.c b/hw/m48t59.c
index c35867d..60bbb00 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -768,10 +768,10 @@ static TypeInfo m48t59_info = {
     .class_init    = m48t59_class_init,
 };
 
-static void m48t59_register_devices(void)
+static void m48t59_register_types(void)
 {
     type_register_static(&m48t59_info);
     type_register_static(&m48t59_isa_info);
 }
 
-device_init(m48t59_register_devices)
+type_init(m48t59_register_types)
diff --git a/hw/macio.c b/hw/macio.c
index 3d648e9..eb15b89 100644
--- a/hw/macio.c
+++ b/hw/macio.c
@@ -97,12 +97,12 @@ static TypeInfo macio_info = {
     .class_init    = macio_class_init,
 };
 
-static void macio_register(void)
+static void macio_register_types(void)
 {
     type_register_static(&macio_info);
 }
 
-device_init(macio_register);
+type_init(macio_register_types)
 
 void macio_init (PCIBus *bus, int device_id, int is_oldworld,
                  MemoryRegion *pic_mem, MemoryRegion *dbdma_mem,
diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c
index b628f17..f6f1937 100644
--- a/hw/marvell_88w8618_audio.c
+++ b/hw/marvell_88w8618_audio.c
@@ -295,9 +295,9 @@ static TypeInfo mv88w8618_audio_info = {
     .class_init    = mv88w8618_audio_class_init,
 };
 
-static void mv88w8618_register_devices(void)
+static void mv88w8618_register_types(void)
 {
     type_register_static(&mv88w8618_audio_info);
 }
 
-device_init(mv88w8618_register_devices)
+type_init(mv88w8618_register_types)
diff --git a/hw/max111x.c b/hw/max111x.c
index 9d61aa9..706d89f 100644
--- a/hw/max111x.c
+++ b/hw/max111x.c
@@ -183,10 +183,10 @@ static TypeInfo max1111_info = {
     .class_init    = max1111_class_init,
 };
 
-static void max111x_register_devices(void)
+static void max111x_register_types(void)
 {
     type_register_static(&max1110_info);
     type_register_static(&max1111_info);
 }
 
-device_init(max111x_register_devices)
+type_init(max111x_register_types)
diff --git a/hw/max7310.c b/hw/max7310.c
index 3a6bb96..1ed18ba 100644
--- a/hw/max7310.c
+++ b/hw/max7310.c
@@ -205,9 +205,9 @@ static TypeInfo max7310_info = {
     .class_init    = max7310_class_init,
 };
 
-static void max7310_register_devices(void)
+static void max7310_register_types(void)
 {
     type_register_static(&max7310_info);
 }
 
-device_init(max7310_register_devices)
+type_init(max7310_register_types)
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 4a43225..6c1ad38 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -733,8 +733,9 @@ static TypeInfo mc146818rtc_info = {
     .class_init    = rtc_class_initfn,
 };
 
-static void mc146818rtc_register(void)
+static void mc146818rtc_register_types(void)
 {
     type_register_static(&mc146818rtc_info);
 }
-device_init(mc146818rtc_register)
+
+type_init(mc146818rtc_register_types)
diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c
index 0881643..4414f39 100644
--- a/hw/milkymist-ac97.c
+++ b/hw/milkymist-ac97.c
@@ -336,9 +336,9 @@ static TypeInfo milkymist_ac97_info = {
     .class_init    = milkymist_ac97_class_init,
 };
 
-static void milkymist_ac97_register(void)
+static void milkymist_ac97_register_types(void)
 {
     type_register_static(&milkymist_ac97_info);
 }
 
-device_init(milkymist_ac97_register)
+type_init(milkymist_ac97_register_types)
diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c
index b5122af..2da0293 100644
--- a/hw/milkymist-hpdmc.c
+++ b/hw/milkymist-hpdmc.c
@@ -162,9 +162,9 @@ static TypeInfo milkymist_hpdmc_info = {
     .class_init    = milkymist_hpdmc_class_init,
 };
 
-static void milkymist_hpdmc_register(void)
+static void milkymist_hpdmc_register_types(void)
 {
     type_register_static(&milkymist_hpdmc_info);
 }
 
-device_init(milkymist_hpdmc_register)
+type_init(milkymist_hpdmc_register_types)
diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c
index 3c1c68a..3515c3c 100644
--- a/hw/milkymist-memcard.c
+++ b/hw/milkymist-memcard.c
@@ -295,9 +295,9 @@ static TypeInfo milkymist_memcard_info = {
     .class_init    = milkymist_memcard_class_init,
 };
 
-static void milkymist_memcard_register(void)
+static void milkymist_memcard_register_types(void)
 {
     type_register_static(&milkymist_memcard_info);
 }
 
-device_init(milkymist_memcard_register)
+type_init(milkymist_memcard_register_types)
diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c
index b9b553f..70bf336 100644
--- a/hw/milkymist-minimac2.c
+++ b/hw/milkymist-minimac2.c
@@ -542,9 +542,9 @@ static TypeInfo milkymist_minimac2_info = {
     .class_init    = milkymist_minimac2_class_init,
 };
 
-static void milkymist_minimac2_register(void)
+static void milkymist_minimac2_register_types(void)
 {
     type_register_static(&milkymist_minimac2_info);
 }
 
-device_init(milkymist_minimac2_register)
+type_init(milkymist_minimac2_register_types)
diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c
index 1b73a46..0f9ff4a 100644
--- a/hw/milkymist-pfpu.c
+++ b/hw/milkymist-pfpu.c
@@ -536,9 +536,9 @@ static TypeInfo milkymist_pfpu_info = {
     .class_init    = milkymist_pfpu_class_init,
 };
 
-static void milkymist_pfpu_register(void)
+static void milkymist_pfpu_register_types(void)
 {
     type_register_static(&milkymist_pfpu_info);
 }
 
-device_init(milkymist_pfpu_register)
+type_init(milkymist_pfpu_register_types)
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
index 5d496cb..ecc2be9 100644
--- a/hw/milkymist-softusb.c
+++ b/hw/milkymist-softusb.c
@@ -323,9 +323,9 @@ static TypeInfo milkymist_softusb_info = {
     .class_init    = milkymist_softusb_class_init,
 };
 
-static void milkymist_softusb_register(void)
+static void milkymist_softusb_register_types(void)
 {
     type_register_static(&milkymist_softusb_info);
 }
 
-device_init(milkymist_softusb_register)
+type_init(milkymist_softusb_register_types)
diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c
index 18171f6..a88548e 100644
--- a/hw/milkymist-sysctl.c
+++ b/hw/milkymist-sysctl.c
@@ -322,9 +322,9 @@ static TypeInfo milkymist_sysctl_info = {
     .class_init    = milkymist_sysctl_class_init,
 };
 
-static void milkymist_sysctl_register(void)
+static void milkymist_sysctl_register_types(void)
 {
     type_register_static(&milkymist_sysctl_info);
 }
 
-device_init(milkymist_sysctl_register)
+type_init(milkymist_sysctl_register_types)
diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c
index 474eae0..210ceed 100644
--- a/hw/milkymist-tmu2.c
+++ b/hw/milkymist-tmu2.c
@@ -482,9 +482,9 @@ static TypeInfo milkymist_tmu2_info = {
     .class_init    = milkymist_tmu2_class_init,
 };
 
-static void milkymist_tmu2_register(void)
+static void milkymist_tmu2_register_types(void)
 {
     type_register_static(&milkymist_tmu2_info);
 }
 
-device_init(milkymist_tmu2_register)
+type_init(milkymist_tmu2_register_types)
diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c
index f9a229c..291fe3c 100644
--- a/hw/milkymist-uart.c
+++ b/hw/milkymist-uart.c
@@ -235,9 +235,9 @@ static TypeInfo milkymist_uart_info = {
     .class_init    = milkymist_uart_class_init,
 };
 
-static void milkymist_uart_register(void)
+static void milkymist_uart_register_types(void)
 {
     type_register_static(&milkymist_uart_info);
 }
 
-device_init(milkymist_uart_register)
+type_init(milkymist_uart_register_types)
diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c
index 92ad02f..69afd72 100644
--- a/hw/milkymist-vgafb.c
+++ b/hw/milkymist-vgafb.c
@@ -323,9 +323,9 @@ static TypeInfo milkymist_vgafb_info = {
     .class_init    = milkymist_vgafb_class_init,
 };
 
-static void milkymist_vgafb_register(void)
+static void milkymist_vgafb_register_types(void)
 {
     type_register_static(&milkymist_vgafb_info);
 }
 
-device_init(milkymist_vgafb_register)
+type_init(milkymist_vgafb_register_types)
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index d232630..ffecefd 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -1029,7 +1029,7 @@ static QEMUMachine mips_malta_machine = {
     .is_default = 1,
 };
 
-static void mips_malta_device_init(void)
+static void mips_malta_register_types(void)
 {
     type_register_static(&mips_malta_device);
 }
@@ -1039,5 +1039,5 @@ static void mips_malta_machine_init(void)
     qemu_register_machine(&mips_malta_machine);
 }
 
-device_init(mips_malta_device_init);
+type_init(mips_malta_register_types)
 machine_init(mips_malta_machine_init);
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index a0e6c9f..50d92f8 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -276,9 +276,9 @@ static TypeInfo mipsnet_info = {
     .class_init    = mipsnet_class_init,
 };
 
-static void mipsnet_register_devices(void)
+static void mipsnet_register_types(void)
 {
     type_register_static(&mipsnet_info);
 }
 
-device_init(mipsnet_register_devices)
+type_init(mipsnet_register_types)
diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c
index 28cd60d..aeb2de7 100644
--- a/hw/mpc8544_guts.c
+++ b/hw/mpc8544_guts.c
@@ -135,8 +135,9 @@ static TypeInfo mpc8544_guts_info = {
     .class_init    = mpc8544_guts_class_init,
 };
 
-static void mpc8544_guts_register(void)
+static void mpc8544_guts_register_types(void)
 {
     type_register_static(&mpc8544_guts_info);
 }
-device_init(mpc8544_guts_register);
+
+type_init(mpc8544_guts_register_types)
diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c
index 1729db0..024192d 100644
--- a/hw/mst_fpga.c
+++ b/hw/mst_fpga.c
@@ -255,8 +255,9 @@ static TypeInfo mst_fpga_info = {
     .class_init    = mst_fpga_class_init,
 };
 
-static void mst_fpga_register(void)
+static void mst_fpga_register_types(void)
 {
     type_register_static(&mst_fpga_info);
 }
-device_init(mst_fpga_register);
+
+type_init(mst_fpga_register_types)
diff --git a/hw/musicpal.c b/hw/musicpal.c
index ac90924..187a1ae 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -1681,7 +1681,7 @@ static TypeInfo mv88w8618_wlan_info = {
     .class_init    = mv88w8618_wlan_class_init,
 };
 
-static void musicpal_register_devices(void)
+static void musicpal_register_types(void)
 {
     type_register_static(&mv88w8618_pic_info);
     type_register_static(&mv88w8618_pit_info);
@@ -1693,4 +1693,4 @@ static void musicpal_register_devices(void)
     type_register_static(&musicpal_key_info);
 }
 
-device_init(musicpal_register_devices)
+type_init(musicpal_register_types)
diff --git a/hw/nand.c b/hw/nand.c
index 5d947b1..e9501ae 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -442,7 +442,7 @@ static TypeInfo nand_info = {
     .class_init    = nand_class_init,
 };
 
-static void nand_create_device(void)
+static void nand_register_types(void)
 {
     type_register_static(&nand_info);
 }
@@ -635,7 +635,7 @@ DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
     return dev;
 }
 
-device_init(nand_create_device)
+type_init(nand_register_types)
 
 #else
 
diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c
index 1352282..a4a783a 100644
--- a/hw/ne2000-isa.c
+++ b/hw/ne2000-isa.c
@@ -104,9 +104,9 @@ static TypeInfo ne2000_isa_info = {
     .class_init    = isa_ne2000_class_initfn,
 };
 
-static void ne2000_isa_register_devices(void)
+static void ne2000_isa_register_types(void)
 {
     type_register_static(&ne2000_isa_info);
 }
 
-device_init(ne2000_isa_register_devices)
+type_init(ne2000_isa_register_types)
diff --git a/hw/ne2000.c b/hw/ne2000.c
index 080811e..bb84fd1 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -812,9 +812,9 @@ static TypeInfo ne2000_info = {
     .class_init    = ne2000_class_init,
 };
 
-static void ne2000_register_devices(void)
+static void ne2000_register_types(void)
 {
     type_register_static(&ne2000_info);
 }
 
-device_init(ne2000_register_devices)
+type_init(ne2000_register_types)
diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c
index 9a9a8e1..201ff77 100644
--- a/hw/omap_gpio.c
+++ b/hw/omap_gpio.c
@@ -783,10 +783,10 @@ static TypeInfo omap2_gpio_info = {
     .class_init    = omap2_gpio_class_init,
 };
 
-static void omap_gpio_register_device(void)
+static void omap_gpio_register_types(void)
 {
     type_register_static(&omap_gpio_info);
     type_register_static(&omap2_gpio_info);
 }
 
-device_init(omap_gpio_register_device)
+type_init(omap_gpio_register_types)
diff --git a/hw/omap_intc.c b/hw/omap_intc.c
index 5aa98a8..5076e07 100644
--- a/hw/omap_intc.c
+++ b/hw/omap_intc.c
@@ -640,10 +640,10 @@ static TypeInfo omap2_intc_info = {
     .class_init    = omap2_intc_class_init,
 };
 
-static void omap_intc_register_device(void)
+static void omap_intc_register_types(void)
 {
     type_register_static(&omap_intc_info);
     type_register_static(&omap2_intc_info);
 }
 
-device_init(omap_intc_register_device)
+type_init(omap_intc_register_types)
diff --git a/hw/onenand.c b/hw/onenand.c
index 8744b04..db6af68 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -828,7 +828,7 @@ static TypeInfo onenand_info = {
     .class_init    = onenand_class_init,
 };
 
-static void onenand_register_device(void)
+static void onenand_register_types(void)
 {
     type_register_static(&onenand_info);
 }
@@ -838,4 +838,4 @@ void *onenand_raw_otp(DeviceState *onenand_device)
     return FROM_SYSBUS(OneNANDState, sysbus_from_qdev(onenand_device))->otp;
 }
 
-device_init(onenand_register_device)
+type_init(onenand_register_types)
diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c
index 09f2757..9b036cb 100644
--- a/hw/opencores_eth.c
+++ b/hw/opencores_eth.c
@@ -750,9 +750,9 @@ static TypeInfo open_eth_info = {
     .class_init    = open_eth_class_init,
 };
 
-static void open_eth_register_devices(void)
+static void open_eth_register_types(void)
 {
     type_register_static(&open_eth_info);
 }
 
-device_init(open_eth_register_devices)
+type_init(open_eth_register_types)
diff --git a/hw/parallel.c b/hw/parallel.c
index 484d727..219f384 100644
--- a/hw/parallel.c
+++ b/hw/parallel.c
@@ -606,9 +606,9 @@ static TypeInfo parallel_isa_info = {
     .class_init    = parallel_isa_class_initfn,
 };
 
-static void parallel_register_devices(void)
+static void parallel_register_types(void)
 {
     type_register_static(&parallel_isa_info);
 }
 
-device_init(parallel_register_devices)
+type_init(parallel_register_types)
diff --git a/hw/pc.c b/hw/pc.c
index 7f3aa65..8d8f59b 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -514,11 +514,12 @@ static TypeInfo port92_info = {
     .class_init    = port92_class_initfn,
 };
 
-static void port92_register(void)
+static void port92_register_types(void)
 {
     type_register_static(&port92_info);
 }
-device_init(port92_register)
+
+type_init(port92_register_types)
 
 static void handle_a20_line_change(void *opaque, int irq, int level)
 {
diff --git a/hw/pci.c b/hw/pci.c
index 5f4f80e..678a8c1 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -2003,9 +2003,9 @@ static TypeInfo pci_device_type_info = {
     .class_init = pci_device_class_init,
 };
 
-static void pci_register_devices(void)
+static void pci_register_types(void)
 {
     type_register_static(&pci_device_type_info);
 }
 
-device_init(pci_register_devices);
+type_init(pci_register_types)
diff --git a/hw/pckbd.c b/hw/pckbd.c
index b4c53be..69857ba 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -513,8 +513,9 @@ static TypeInfo i8042_info = {
     .class_init    = i8042_class_initfn,
 };
 
-static void i8042_register(void)
+static void i8042_register_types(void)
 {
     type_register_static(&i8042_info);
 }
-device_init(i8042_register)
+
+type_init(i8042_register_types)
diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c
index 439f32c..3682609 100644
--- a/hw/pcnet-pci.c
+++ b/hw/pcnet-pci.c
@@ -376,9 +376,9 @@ static TypeInfo pcnet_info = {
     .class_init    = pcnet_class_init,
 };
 
-static void pci_pcnet_register_devices(void)
+static void pci_pcnet_register_types(void)
 {
     type_register_static(&pcnet_info);
 }
 
-device_init(pci_pcnet_register_devices)
+type_init(pci_pcnet_register_types)
diff --git a/hw/piix4.c b/hw/piix4.c
index 4e7a237..ce4eb0d 100644
--- a/hw/piix4.c
+++ b/hw/piix4.c
@@ -124,8 +124,9 @@ static TypeInfo piix4_info = {
     .class_init    = piix4_class_init,
 };
 
-static void piix4_register(void)
+static void piix4_register_types(void)
 {
     type_register_static(&piix4_info);
 }
-device_init(piix4_register);
+
+type_init(piix4_register_types)
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 1906427..e0268fe 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -589,11 +589,12 @@ static TypeInfo i440fx_pcihost_info = {
     .class_init    = i440fx_pcihost_class_init,
 };
 
-static void i440fx_register(void)
+static void i440fx_register_types(void)
 {
     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);
+
+type_init(i440fx_register_types)
diff --git a/hw/pl011.c b/hw/pl011.c
index 752cbf9..8a5a8f5 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -316,10 +316,10 @@ static TypeInfo pl011_luminary_info = {
     .class_init    = pl011_luminary_class_init,
 };
 
-static void pl011_register_devices(void)
+static void pl011_register_types(void)
 {
     type_register_static(&pl011_arm_info);
     type_register_static(&pl011_luminary_info);
 }
 
-device_init(pl011_register_devices)
+type_init(pl011_register_types)
diff --git a/hw/pl022.c b/hw/pl022.c
index 30bd344..03bf63c 100644
--- a/hw/pl022.c
+++ b/hw/pl022.c
@@ -299,9 +299,9 @@ static TypeInfo pl022_info = {
     .class_init    = pl022_class_init,
 };
 
-static void pl022_register_devices(void)
+static void pl022_register_types(void)
 {
     type_register_static(&pl022_info);
 }
 
-device_init(pl022_register_devices)
+type_init(pl022_register_types)
diff --git a/hw/pl031.c b/hw/pl031.c
index 8416a60..05b5b11 100644
--- a/hw/pl031.c
+++ b/hw/pl031.c
@@ -230,9 +230,9 @@ static TypeInfo pl031_info = {
     .class_init    = pl031_class_init,
 };
 
-static void pl031_register_devices(void)
+static void pl031_register_types(void)
 {
     type_register_static(&pl031_info);
 }
 
-device_init(pl031_register_devices)
+type_init(pl031_register_types)
diff --git a/hw/pl041.c b/hw/pl041.c
index 6d99c9c..b6723be 100644
--- a/hw/pl041.c
+++ b/hw/pl041.c
@@ -638,9 +638,9 @@ static TypeInfo pl041_device_info = {
     .class_init    = pl041_device_class_init,
 };
 
-static void pl041_register_device(void)
+static void pl041_register_types(void)
 {
     type_register_static(&pl041_device_info);
 }
 
-device_init(pl041_register_device)
+type_init(pl041_register_types)
diff --git a/hw/pl050.c b/hw/pl050.c
index b0094ac..b13924a 100644
--- a/hw/pl050.c
+++ b/hw/pl050.c
@@ -189,10 +189,10 @@ static TypeInfo pl050_mouse_info = {
     .class_init    = pl050_mouse_class_init,
 };
 
-static void pl050_register_devices(void)
+static void pl050_register_types(void)
 {
     type_register_static(&pl050_kbd_info);
     type_register_static(&pl050_mouse_info);
 }
 
-device_init(pl050_register_devices)
+type_init(pl050_register_types)
diff --git a/hw/pl061.c b/hw/pl061.c
index 3136c99..2aac7e8 100644
--- a/hw/pl061.c
+++ b/hw/pl061.c
@@ -325,10 +325,10 @@ static TypeInfo pl061_luminary_info = {
     .class_init    = pl061_luminary_class_init,
 };
 
-static void pl061_register_devices(void)
+static void pl061_register_types(void)
 {
     type_register_static(&pl061_info);
     type_register_static(&pl061_luminary_info);
 }
 
-device_init(pl061_register_devices)
+type_init(pl061_register_types)
diff --git a/hw/pl080.c b/hw/pl080.c
index 4405d18..b3cf651 100644
--- a/hw/pl080.c
+++ b/hw/pl080.c
@@ -409,10 +409,10 @@ static TypeInfo pl081_info = {
 
 /* 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)
+static void pl080_register_types(void)
 {
     type_register_static(&pl080_info);
     type_register_static(&pl081_info);
 }
 
-device_init(pl080_register_devices)
+type_init(pl080_register_types)
diff --git a/hw/pl110.c b/hw/pl110.c
index 86e95a3..f94608c 100644
--- a/hw/pl110.c
+++ b/hw/pl110.c
@@ -520,11 +520,11 @@ static TypeInfo pl111_info = {
     .class_init    = pl111_class_init,
 };
 
-static void pl110_register_devices(void)
+static void pl110_register_types(void)
 {
     type_register_static(&pl110_info);
     type_register_static(&pl110_versatile_info);
     type_register_static(&pl111_info);
 }
 
-device_init(pl110_register_devices)
+type_init(pl110_register_types)
diff --git a/hw/pl181.c b/hw/pl181.c
index ae636e2..7d91fbb 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -505,9 +505,9 @@ static TypeInfo pl181_info = {
     .class_init    = pl181_class_init,
 };
 
-static void pl181_register_devices(void)
+static void pl181_register_types(void)
 {
     type_register_static(&pl181_info);
 }
 
-device_init(pl181_register_devices)
+type_init(pl181_register_types)
diff --git a/hw/pl190.c b/hw/pl190.c
index 956ab21..cb50afb 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -273,9 +273,9 @@ static TypeInfo pl190_info = {
     .class_init    = pl190_class_init,
 };
 
-static void pl190_register_devices(void)
+static void pl190_register_types(void)
 {
     type_register_static(&pl190_info);
 }
 
-device_init(pl190_register_devices)
+type_init(pl190_register_types)
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index d11f120..203c3cd 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -400,9 +400,10 @@ static TypeInfo ppc4xx_pcihost_info = {
     .class_init    = ppc4xx_pcihost_class_init,
 };
 
-static void ppc4xx_pci_register(void)
+static void ppc4xx_pci_register_types(void)
 {
     type_register_static(&ppc4xx_pcihost_info);
     type_register_static(&ppc4xx_host_bridge_info);
 }
-device_init(ppc4xx_pci_register);
+
+type_init(ppc4xx_pci_register_types)
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index d5bce71..0f60b24 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -373,9 +373,10 @@ static TypeInfo e500_pcihost_info = {
     .class_init    = e500_pcihost_class_init,
 };
 
-static void e500_pci_register(void)
+static void e500_pci_register_types(void)
 {
     type_register_static(&e500_pcihost_info);
     type_register_static(&e500_host_bridge_info);
 }
-device_init(e500_pci_register);
+
+type_init(e500_pci_register_types)
diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c
index 9d648ec..6b8a189 100644
--- a/hw/ppce500_spin.c
+++ b/hw/ppce500_spin.c
@@ -217,8 +217,9 @@ static TypeInfo ppce500_spin_info = {
     .class_init    = ppce500_spin_class_init,
 };
 
-static void ppce500_spin_register(void)
+static void ppce500_spin_register_types(void)
 {
     type_register_static(&ppce500_spin_info);
 }
-device_init(ppce500_spin_register);
+
+type_init(ppce500_spin_register_types)
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index 40b8bb0..8b29da9 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -173,10 +173,10 @@ static TypeInfo raven_pcihost_info = {
     .class_init = raven_pcihost_class_init,
 };
 
-static void raven_register_devices(void)
+static void raven_register_types(void)
 {
     type_register_static(&raven_pcihost_info);
     type_register_static(&raven_info);
 }
 
-device_init(raven_register_devices)
+type_init(raven_register_types)
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 244c614..1ab2701 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -2330,7 +2330,7 @@ static TypeInfo pxa2xx_ssp_info = {
     .class_init    = pxa2xx_ssp_class_init,
 };
 
-static void pxa2xx_register_devices(void)
+static void pxa2xx_register_types(void)
 {
     type_register_static(&pxa2xx_i2c_slave_info);
     type_register_static(&pxa2xx_ssp_info);
@@ -2338,4 +2338,4 @@ static void pxa2xx_register_devices(void)
     type_register_static(&pxa2xx_rtc_sysbus_info);
 }
 
-device_init(pxa2xx_register_devices)
+type_init(pxa2xx_register_types)
diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c
index 2d61565..8ced0dd 100644
--- a/hw/pxa2xx_dma.c
+++ b/hw/pxa2xx_dma.c
@@ -566,8 +566,9 @@ static TypeInfo pxa2xx_dma_info = {
     .class_init    = pxa2xx_dma_class_init,
 };
 
-static void pxa2xx_dma_register(void)
+static void pxa2xx_dma_register_types(void)
 {
     type_register_static(&pxa2xx_dma_info);
 }
-device_init(pxa2xx_dma_register);
+
+type_init(pxa2xx_dma_register_types)
diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c
index 67fd17c..d5f5716 100644
--- a/hw/pxa2xx_gpio.c
+++ b/hw/pxa2xx_gpio.c
@@ -340,8 +340,9 @@ static TypeInfo pxa2xx_gpio_info = {
     .class_init    = pxa2xx_gpio_class_init,
 };
 
-static void pxa2xx_gpio_register(void)
+static void pxa2xx_gpio_register_types(void)
 {
     type_register_static(&pxa2xx_gpio_info);
 }
-device_init(pxa2xx_gpio_register);
+
+type_init(pxa2xx_gpio_register_types)
diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c
index ca85743..6b2bdb0 100644
--- a/hw/pxa2xx_pic.c
+++ b/hw/pxa2xx_pic.c
@@ -313,8 +313,9 @@ static TypeInfo pxa2xx_pic_info = {
     .class_init    = pxa2xx_pic_class_init,
 };
 
-static void pxa2xx_pic_register(void)
+static void pxa2xx_pic_register_types(void)
 {
     type_register_static(&pxa2xx_pic_info);
 }
-device_init(pxa2xx_pic_register);
+
+type_init(pxa2xx_pic_register_types)
diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c
index 9080075..77b033b 100644
--- a/hw/pxa2xx_timer.c
+++ b/hw/pxa2xx_timer.c
@@ -527,9 +527,10 @@ static TypeInfo pxa27x_timer_dev_info = {
     .class_init    = pxa27x_timer_dev_class_init,
 };
 
-static void pxa2xx_timer_register(void)
+static void pxa2xx_timer_register_types(void)
 {
     type_register_static(&pxa25x_timer_dev_info);
     type_register_static(&pxa27x_timer_dev_info);
-};
-device_init(pxa2xx_timer_register);
+}
+
+type_init(pxa2xx_timer_register_types)
diff --git a/hw/qdev.c b/hw/qdev.c
index 8a413ef..f0eb3a7 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -665,9 +665,9 @@ static TypeInfo device_type_info = {
     .class_size = sizeof(DeviceClass),
 };
 
-static void init_qdev(void)
+static void qdev_register_types(void)
 {
     type_register_static(&device_type_info);
 }
 
-device_init(init_qdev);
+type_init(qdev_register_types)
diff --git a/hw/qxl.c b/hw/qxl.c
index bc03c1d..ac69125 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1870,10 +1870,10 @@ static TypeInfo qxl_secondary_info = {
     .class_init    = qxl_secondary_class_init,
 };
 
-static void qxl_register(void)
+static void qxl_register_types(void)
 {
     type_register_static(&qxl_primary_info);
     type_register_static(&qxl_secondary_info);
 }
 
-device_init(qxl_register);
+type_init(qxl_register_types)
diff --git a/hw/realview.c b/hw/realview.c
index 8b0b03d..bcf982f 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -96,7 +96,7 @@ static TypeInfo realview_i2c_info = {
     .class_init    = realview_i2c_class_init,
 };
 
-static void realview_register_devices(void)
+static void realview_register_types(void)
 {
     type_register_static(&realview_i2c_info);
 }
@@ -491,4 +491,4 @@ static void realview_machine_init(void)
 }
 
 machine_init(realview_machine_init);
-device_init(realview_register_devices)
+type_init(realview_register_types)
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index 4121502..071ef13 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -60,9 +60,9 @@ static TypeInfo realview_gic_info = {
     .class_init    = realview_gic_class_init,
 };
 
-static void realview_gic_register_devices(void)
+static void realview_gic_register_types(void)
 {
     type_register_static(&realview_gic_info);
 }
 
-device_init(realview_gic_register_devices)
+type_init(realview_gic_register_types)
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 1668390..05b8e1e 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -3523,9 +3523,9 @@ static TypeInfo rtl8139_info = {
     .class_init    = rtl8139_class_init,
 };
 
-static void rtl8139_register_devices(void)
+static void rtl8139_register_types(void)
 {
     type_register_static(&rtl8139_info);
 }
 
-device_init(rtl8139_register_devices)
+type_init(rtl8139_register_types)
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index 49140f8..9d48056 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -433,15 +433,6 @@ static TypeInfo virtio_s390_device_info = {
     .abstract = true,
 };
 
-static void s390_virtio_register(void)
-{
-    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);
-
 
 /***************** S390 Virtio Bus Bridge Device *******************/
 /* Only required to have the virtio bus as child in the system bus */
@@ -468,9 +459,13 @@ static TypeInfo s390_virtio_bridge_info = {
     .class_init    = s390_virtio_bridge_class_init,
 };
 
-static void s390_virtio_register_devices(void)
+static void s390_virtio_register_types(void)
 {
+    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);
     type_register_static(&s390_virtio_bridge_info);
 }
 
-device_init(s390_virtio_register_devices)
+type_init(s390_virtio_register_types)
diff --git a/hw/sb16.c b/hw/sb16.c
index db8929b..c81455d 100644
--- a/hw/sb16.c
+++ b/hw/sb16.c
@@ -1417,8 +1417,9 @@ static TypeInfo sb16_info = {
     .class_init    = sb16_class_initfn,
 };
 
-static void sb16_register (void)
+static void sb16_register_types (void)
 {
     type_register_static (&sb16_info);
 }
-device_init (sb16_register)
+
+type_init (sb16_register_types)
diff --git a/hw/sbi.c b/hw/sbi.c
index 847a4dd..52982a9 100644
--- a/hw/sbi.c
+++ b/hw/sbi.c
@@ -148,9 +148,9 @@ static TypeInfo sbi_info = {
     .class_init    = sbi_class_init,
 };
 
-static void sbi_register_devices(void)
+static void sbi_register_types(void)
 {
     type_register_static(&sbi_info);
 }
 
-device_init(sbi_register_devices)
+type_init(sbi_register_types)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 0ee50a8..b3e97ce 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -1431,9 +1431,9 @@ static TypeInfo scsi_device_type_info = {
     .class_init = scsi_device_class_init,
 };
 
-static void scsi_register_devices(void)
+static void scsi_register_types(void)
 {
     type_register_static(&scsi_device_type_info);
 }
 
-device_init(scsi_register_devices);
+type_init(scsi_register_types)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 399e51e..c12e3a6 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1823,7 +1823,7 @@ static TypeInfo scsi_disk_info = {
     .class_init    = scsi_disk_class_initfn,
 };
 
-static void scsi_disk_register_devices(void)
+static void scsi_disk_register_types(void)
 {
     type_register_static(&scsi_hd_info);
     type_register_static(&scsi_cd_info);
@@ -1832,4 +1832,5 @@ static void scsi_disk_register_devices(void)
 #endif
     type_register_static(&scsi_disk_info);
 }
-device_init(scsi_disk_register_devices)
+
+type_init(scsi_disk_register_types)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 4859212..86014aa 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -483,10 +483,11 @@ static TypeInfo scsi_generic_info = {
     .class_init    = scsi_generic_class_initfn,
 };
 
-static void scsi_generic_register_devices(void)
+static void scsi_generic_register_types(void)
 {
     type_register_static(&scsi_generic_info);
 }
-device_init(scsi_generic_register_devices)
+
+type_init(scsi_generic_register_types)
 
 #endif /* __linux__ */
diff --git a/hw/serial.c b/hw/serial.c
index 82917e2..144d1b3 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -903,9 +903,9 @@ static TypeInfo serial_isa_info = {
     .class_init    = serial_isa_class_initfn,
 };
 
-static void serial_register_devices(void)
+static void serial_register_types(void)
 {
     type_register_static(&serial_isa_info);
 }
 
-device_init(serial_register_devices)
+type_init(serial_register_types)
diff --git a/hw/sga.c b/hw/sga.c
index b08e3c5..a666349 100644
--- a/hw/sga.c
+++ b/hw/sga.c
@@ -55,9 +55,9 @@ static TypeInfo sga_info = {
     .class_init    = sga_class_initfn,
 };
 
-static void sga_register(void)
+static void sga_register_types(void)
 {
     type_register_static(&sga_info);
 }
 
-device_init(sga_register);
+type_init(sga_register_types)
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
index 4234d93..0cfac46 100644
--- a/hw/sh_pci.c
+++ b/hw/sh_pci.c
@@ -177,10 +177,10 @@ static TypeInfo sh_pci_device_info = {
     .class_init    = sh_pci_device_class_init,
 };
 
-static void sh_pci_register_devices(void)
+static void sh_pci_register_types(void)
 {
     type_register_static(&sh_pci_device_info);
     type_register_static(&sh_pci_host_info);
 }
 
-device_init(sh_pci_register_devices)
+type_init(sh_pci_register_types)
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c
index e3701c7..7fdc3be 100644
--- a/hw/slavio_intctl.c
+++ b/hw/slavio_intctl.c
@@ -463,9 +463,9 @@ static TypeInfo slavio_intctl_info = {
     .class_init    = slavio_intctl_class_init,
 };
 
-static void slavio_intctl_register_devices(void)
+static void slavio_intctl_register_types(void)
 {
     type_register_static(&slavio_intctl_info);
 }
 
-device_init(slavio_intctl_register_devices)
+type_init(slavio_intctl_register_types)
diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c
index 5a02518..944835e 100644
--- a/hw/slavio_misc.c
+++ b/hw/slavio_misc.c
@@ -499,10 +499,10 @@ static TypeInfo apc_info = {
     .class_init    = apc_class_init,
 };
 
-static void slavio_misc_register_devices(void)
+static void slavio_misc_register_types(void)
 {
     type_register_static(&slavio_misc_info);
     type_register_static(&apc_info);
 }
 
-device_init(slavio_misc_register_devices)
+type_init(slavio_misc_register_types)
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
index 3878f6f..97edebb 100644
--- a/hw/slavio_timer.c
+++ b/hw/slavio_timer.c
@@ -427,9 +427,9 @@ static TypeInfo slavio_timer_info = {
     .class_init    = slavio_timer_class_init,
 };
 
-static void slavio_timer_register_devices(void)
+static void slavio_timer_register_types(void)
 {
     type_register_static(&slavio_timer_info);
 }
 
-device_init(slavio_timer_register_devices)
+type_init(slavio_timer_register_types)
diff --git a/hw/smbus.c b/hw/smbus.c
index 77626f3..e3cf6a2 100644
--- a/hw/smbus.c
+++ b/hw/smbus.c
@@ -327,9 +327,9 @@ static TypeInfo smbus_device_type_info = {
     .class_init = smbus_device_class_init,
 };
 
-static void smbus_device_register_devices(void)
+static void smbus_device_register_types(void)
 {
     type_register_static(&smbus_device_type_info);
 }
 
-device_init(smbus_device_register_devices);
+type_init(smbus_device_register_types)
diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c
index 9d96cbe..11adab0 100644
--- a/hw/smbus_eeprom.c
+++ b/hw/smbus_eeprom.c
@@ -130,12 +130,12 @@ static TypeInfo smbus_eeprom_info = {
     .class_init    = smbus_eeprom_class_initfn,
 };
 
-static void smbus_eeprom_register_devices(void)
+static void smbus_eeprom_register_types(void)
 {
     type_register_static(&smbus_eeprom_info);
 }
 
-device_init(smbus_eeprom_register_devices)
+type_init(smbus_eeprom_register_types)
 
 void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom,
                        const uint8_t *eeprom_spd, int eeprom_spd_size)
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index 1bf2901..1a5213f 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -781,7 +781,7 @@ static TypeInfo smc91c111_info = {
     .class_init    = smc91c111_class_init,
 };
 
-static void smc91c111_register_devices(void)
+static void smc91c111_register_types(void)
 {
     type_register_static(&smc91c111_info);
 }
@@ -802,4 +802,4 @@ void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
     sysbus_connect_irq(s, 0, irq);
 }
 
-device_init(smc91c111_register_devices)
+type_init(smc91c111_register_types)
diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
index 84281be..6ac7384 100644
--- a/hw/spapr_hcall.c
+++ b/hw/spapr_hcall.c
@@ -672,7 +672,7 @@ target_ulong spapr_hypercall(CPUState *env, target_ulong opcode,
     return H_FUNCTION;
 }
 
-static void hypercall_init(void)
+static void hypercall_register_types(void)
 {
     /* hcall-pft */
     spapr_register_hypercall(H_ENTER, h_enter);
@@ -704,4 +704,5 @@ static void hypercall_init(void)
     /* qemu/KVM-PPC specific hcalls */
     spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
 }
-device_init(hypercall_init);
+
+type_init(hypercall_register_types)
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
index 79b3941..77d4047 100644
--- a/hw/spapr_llan.c
+++ b/hw/spapr_llan.c
@@ -501,7 +501,7 @@ static TypeInfo spapr_vlan_info = {
     .class_init    = spapr_vlan_class_init,
 };
 
-static void spapr_vlan_register(void)
+static void spapr_vlan_register_types(void)
 {
     spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
     spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
@@ -511,4 +511,5 @@ static void spapr_vlan_register(void)
     spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
     type_register_static(&spapr_vlan_info);
 }
-device_init(spapr_vlan_register);
+
+type_init(spapr_vlan_register_types)
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index ed2e4b3..cfdd9dd 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -242,13 +242,13 @@ static TypeInfo spapr_phb_info = {
     .class_init    = spapr_phb_class_init,
 };
 
-static void spapr_register_devices(void)
+static void spapr_register_types(void)
 {
     type_register_static(&spapr_phb_info);
     type_register_static(&spapr_main_pci_host_info);
 }
 
-device_init(spapr_register_devices)
+type_init(spapr_register_types)
 
 static uint64_t spapr_io_read(void *opaque, target_phys_addr_t addr,
                               unsigned size)
diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c
index d1ac74c..c0723b3 100644
--- a/hw/spapr_rtas.c
+++ b/hw/spapr_rtas.c
@@ -288,7 +288,7 @@ int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr,
     return 0;
 }
 
-static void register_core_rtas(void)
+static void core_rtas_register_types(void)
 {
     spapr_rtas_register("display-character", rtas_display_character);
     spapr_rtas_register("get-time-of-day", rtas_get_time_of_day);
@@ -298,4 +298,5 @@ static void register_core_rtas(void)
                         rtas_query_cpu_stopped_state);
     spapr_rtas_register("start-cpu", rtas_start_cpu);
 }
-device_init(register_core_rtas);
+
+type_init(core_rtas_register_types)
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 64f0009..ea317ef 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -778,13 +778,13 @@ static TypeInfo spapr_vio_type_info = {
     .class_init = vio_spapr_device_class_init,
 };
 
-static void spapr_vio_register_devices(void)
+static void spapr_vio_register_types(void)
 {
     type_register_static(&spapr_vio_bridge_info);
     type_register_static(&spapr_vio_type_info);
 }
 
-device_init(spapr_vio_register_devices)
+type_init(spapr_vio_register_types)
 
 #ifdef CONFIG_FDT
 static int compare_reg(const void *p1, const void *p2)
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 9cfce19..ffce261 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -973,8 +973,9 @@ static TypeInfo spapr_vscsi_info = {
     .class_init    = spapr_vscsi_class_init,
 };
 
-static void spapr_vscsi_register(void)
+static void spapr_vscsi_register_types(void)
 {
     type_register_static(&spapr_vscsi_info);
 }
-device_init(spapr_vscsi_register);
+
+type_init(spapr_vscsi_register_types)
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index a954e7d..3efe242 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -212,10 +212,11 @@ static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
     return sdev;
 }
 
-static void spapr_vty_register(void)
+static void spapr_vty_register_types(void)
 {
     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);
+
+type_init(spapr_vty_register_types)
diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
index f07cc6f..1dbf69e 100644
--- a/hw/sparc32_dma.c
+++ b/hw/sparc32_dma.c
@@ -307,9 +307,9 @@ static TypeInfo sparc32_dma_info = {
     .class_init    = sparc32_dma_class_init,
 };
 
-static void sparc32_dma_register_devices(void)
+static void sparc32_dma_register_types(void)
 {
     type_register_static(&sparc32_dma_info);
 }
 
-device_init(sparc32_dma_register_devices)
+type_init(sparc32_dma_register_types)
diff --git a/hw/spitz.c b/hw/spitz.c
index 4e6540d..1d6d2b0 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -1138,7 +1138,7 @@ static TypeInfo spitz_lcdtg_info = {
     .class_init    = spitz_lcdtg_class_init,
 };
 
-static void spitz_register_devices(void)
+static void spitz_register_types(void)
 {
     type_register_static(&corgi_ssp_info);
     type_register_static(&spitz_lcdtg_info);
@@ -1146,4 +1146,4 @@ static void spitz_register_devices(void)
     type_register_static(&sl_nand_info);
 }
 
-device_init(spitz_register_devices)
+type_init(spitz_register_types)
diff --git a/hw/ssd0303.c b/hw/ssd0303.c
index 685602a..4e1ee6e 100644
--- a/hw/ssd0303.c
+++ b/hw/ssd0303.c
@@ -313,9 +313,9 @@ static TypeInfo ssd0303_info = {
     .class_init    = ssd0303_class_init,
 };
 
-static void ssd0303_register_devices(void)
+static void ssd0303_register_types(void)
 {
     type_register_static(&ssd0303_info);
 }
 
-device_init(ssd0303_register_devices)
+type_init(ssd0303_register_types)
diff --git a/hw/ssd0323.c b/hw/ssd0323.c
index 3c43738..b0b2e94 100644
--- a/hw/ssd0323.c
+++ b/hw/ssd0323.c
@@ -355,9 +355,9 @@ static TypeInfo ssd0323_info = {
     .class_init    = ssd0323_class_init,
 };
 
-static void ssd03232_register_devices(void)
+static void ssd03232_register_types(void)
 {
     type_register_static(&ssd0323_info);
 }
 
-device_init(ssd03232_register_devices)
+type_init(ssd03232_register_types)
diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
index f2e6cec..b519bdb 100644
--- a/hw/ssi-sd.c
+++ b/hw/ssi-sd.c
@@ -259,9 +259,9 @@ static TypeInfo ssi_sd_info = {
     .class_init    = ssi_sd_class_init,
 };
 
-static void ssi_sd_register_devices(void)
+static void ssi_sd_register_types(void)
 {
     type_register_static(&ssi_sd_info);
 }
 
-device_init(ssi_sd_register_devices)
+type_init(ssi_sd_register_types)
diff --git a/hw/ssi.c b/hw/ssi.c
index ead446c..8f2d9bc 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -80,9 +80,9 @@ uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
     return ssc->transfer(slave, val);
 }
 
-static void register_ssi_slave(void)
+static void ssi_slave_register_types(void)
 {
     type_register_static(&ssi_slave_info);
 }
 
-device_init(register_ssi_slave);
+type_init(ssi_slave_register_types)
diff --git a/hw/stellaris.c b/hw/stellaris.c
index 31a65cf..562fbbf 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -1451,7 +1451,7 @@ static TypeInfo stellaris_adc_info = {
     .class_init    = stellaris_adc_class_init,
 };
 
-static void stellaris_register_devices(void)
+static void stellaris_register_types(void)
 {
     type_register_static(&stellaris_i2c_info);
     type_register_static(&stellaris_gptm_info);
@@ -1459,4 +1459,4 @@ static void stellaris_register_devices(void)
     type_register_static(&stellaris_ssi_bus_info);
 }
 
-device_init(stellaris_register_devices)
+type_init(stellaris_register_types)
diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c
index 9b1be8d..fbe99cb 100644
--- a/hw/stellaris_enet.c
+++ b/hw/stellaris_enet.c
@@ -441,9 +441,9 @@ static TypeInfo stellaris_enet_info = {
     .class_init    = stellaris_enet_class_init,
 };
 
-static void stellaris_enet_register_devices(void)
+static void stellaris_enet_register_types(void)
 {
     type_register_static(&stellaris_enet_info);
 }
 
-device_init(stellaris_enet_register_devices)
+type_init(stellaris_enet_register_types)
diff --git a/hw/strongarm.c b/hw/strongarm.c
index 8d2e7eb..4d5b60f 100644
--- a/hw/strongarm.c
+++ b/hw/strongarm.c
@@ -1609,7 +1609,7 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem,
     return s;
 }
 
-static void strongarm_register_devices(void)
+static void strongarm_register_types(void)
 {
     type_register_static(&strongarm_pic_info);
     type_register_static(&strongarm_rtc_sysbus_info);
@@ -1618,4 +1618,5 @@ static void strongarm_register_devices(void)
     type_register_static(&strongarm_uart_info);
     type_register_static(&strongarm_ssp_info);
 }
-device_init(strongarm_register_devices)
+
+type_init(strongarm_register_types)
diff --git a/hw/sun4c_intctl.c b/hw/sun4c_intctl.c
index 081d6cc..8dfa5ec 100644
--- a/hw/sun4c_intctl.c
+++ b/hw/sun4c_intctl.c
@@ -223,9 +223,9 @@ static TypeInfo sun4c_intctl_info = {
     .class_init    = sun4c_intctl_class_init,
 };
 
-static void sun4c_intctl_register_devices(void)
+static void sun4c_intctl_register_types(void)
 {
     type_register_static(&sun4c_intctl_info);
 }
 
-device_init(sun4c_intctl_register_devices)
+type_init(sun4c_intctl_register_types)
diff --git a/hw/sun4m.c b/hw/sun4m.c
index b79d14c..99fb219 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -623,13 +623,6 @@ static TypeInfo idreg_info = {
     .class_init    = idreg_class_init,
 };
 
-static void idreg_register_devices(void)
-{
-    type_register_static(&idreg_info);
-}
-
-device_init(idreg_register_devices);
-
 typedef struct AFXState {
     SysBusDevice busdev;
     MemoryRegion mem;
@@ -672,13 +665,6 @@ static TypeInfo afx_info = {
     .class_init    = afx_class_init,
 };
 
-static void afx_register_devices(void)
-{
-    type_register_static(&afx_info);
-}
-
-device_init(afx_register_devices);
-
 typedef struct PROMState {
     SysBusDevice busdev;
     MemoryRegion prom;
@@ -756,13 +742,6 @@ static TypeInfo prom_info = {
     .class_init    = prom_class_init,
 };
 
-static void prom_register_devices(void)
-{
-    type_register_static(&prom_info);
-}
-
-device_init(prom_register_devices);
-
 typedef struct RamDevice
 {
     SysBusDevice busdev;
@@ -827,13 +806,6 @@ static TypeInfo ram_info = {
     .class_init    = ram_class_init,
 };
 
-static void ram_register_devices(void)
-{
-    type_register_static(&ram_info);
-}
-
-device_init(ram_register_devices);
-
 static void cpu_devinit(const char *cpu_model, unsigned int id,
                         uint64_t prom_addr, qemu_irq **cpu_irqs)
 {
@@ -1865,6 +1837,14 @@ static QEMUMachine ss2_machine = {
     .use_scsi = 1,
 };
 
+static void sun4m_register_types(void)
+{
+    type_register_static(&idreg_info);
+    type_register_static(&afx_info);
+    type_register_static(&prom_info);
+    type_register_static(&ram_info);
+}
+
 static void ss2_machine_init(void)
 {
     qemu_register_machine(&ss5_machine);
@@ -1881,4 +1861,5 @@ static void ss2_machine_init(void)
     qemu_register_machine(&ss2_machine);
 }
 
+type_init(sun4m_register_types)
 machine_init(ss2_machine_init);
diff --git a/hw/sun4m_iommu.c b/hw/sun4m_iommu.c
index 727532c..ebefa91 100644
--- a/hw/sun4m_iommu.c
+++ b/hw/sun4m_iommu.c
@@ -380,9 +380,9 @@ static TypeInfo iommu_info = {
     .class_init    = iommu_class_init,
 };
 
-static void iommu_register_devices(void)
+static void iommu_register_types(void)
 {
     type_register_static(&iommu_info);
 }
 
-device_init(iommu_register_devices)
+type_init(iommu_register_types)
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 79bbd49..423108f 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -580,13 +580,6 @@ static TypeInfo ebus_info = {
     .class_init    = ebus_class_init,
 };
 
-static void pci_ebus_register(void)
-{
-    type_register_static(&ebus_info);
-}
-
-device_init(pci_ebus_register);
-
 typedef struct PROMState {
     SysBusDevice busdev;
     MemoryRegion prom;
@@ -664,13 +657,6 @@ static TypeInfo prom_info = {
     .class_init    = prom_class_init,
 };
 
-static void prom_register_devices(void)
-{
-    type_register_static(&prom_info);
-}
-
-device_init(prom_register_devices);
-
 
 typedef struct RamDevice
 {
@@ -728,13 +714,6 @@ static TypeInfo ram_info = {
     .class_init    = ram_class_init,
 };
 
-static void ram_register_devices(void)
-{
-    type_register_static(&ram_info);
-}
-
-device_init(ram_register_devices);
-
 static CPUState *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef)
 {
     CPUState *env;
@@ -957,6 +936,13 @@ static QEMUMachine niagara_machine = {
     .max_cpus = 1, // XXX for now
 };
 
+static void sun4u_register_types(void)
+{
+    type_register_static(&ebus_info);
+    type_register_static(&prom_info);
+    type_register_static(&ram_info);
+}
+
 static void sun4u_machine_init(void)
 {
     qemu_register_machine(&sun4u_machine);
@@ -964,4 +950,5 @@ static void sun4u_machine_init(void)
     qemu_register_machine(&niagara_machine);
 }
 
+type_init(sun4u_register_types)
 machine_init(sun4u_machine_init);
diff --git a/hw/sysbus.c b/hw/sysbus.c
index 282060a..db4efcc 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -256,9 +256,9 @@ static TypeInfo sysbus_device_type_info = {
     .class_init = sysbus_device_class_init,
 };
 
-static void sysbus_register(void)
+static void sysbus_register_types(void)
 {
     type_register_static(&sysbus_device_type_info);
 }
 
-device_init(sysbus_register);
+type_init(sysbus_register_types)
diff --git a/hw/tcx.c b/hw/tcx.c
index ceb94c7..2b66d86 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -664,9 +664,9 @@ static TypeInfo tcx_info = {
     .class_init    = tcx_class_init,
 };
 
-static void tcx_register_devices(void)
+static void tcx_register_types(void)
 {
     type_register_static(&tcx_info);
 }
 
-device_init(tcx_register_devices)
+type_init(tcx_register_types)
diff --git a/hw/tmp105.c b/hw/tmp105.c
index a3bdd91..8e8dbd9 100644
--- a/hw/tmp105.c
+++ b/hw/tmp105.c
@@ -245,9 +245,9 @@ static TypeInfo tmp105_info = {
     .class_init    = tmp105_class_init,
 };
 
-static void tmp105_register_devices(void)
+static void tmp105_register_types(void)
 {
     type_register_static(&tmp105_info);
 }
 
-device_init(tmp105_register_devices)
+type_init(tmp105_register_types)
diff --git a/hw/tosa.c b/hw/tosa.c
index c0d4017..6baa17d 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -291,10 +291,10 @@ static TypeInfo tosa_ssp_info = {
     .class_init    = tosa_ssp_class_init,
 };
 
-static void tosa_register_devices(void)
+static void tosa_register_types(void)
 {
     type_register_static(&tosa_dac_info);
     type_register_static(&tosa_ssp_info);
 }
 
-device_init(tosa_register_devices)
+type_init(tosa_register_types)
diff --git a/hw/tusb6010.c b/hw/tusb6010.c
index 0ade670..5ba8da6 100644
--- a/hw/tusb6010.c
+++ b/hw/tusb6010.c
@@ -805,9 +805,9 @@ static TypeInfo tusb6010_info = {
     .class_init    = tusb6010_class_init,
 };
 
-static void tusb6010_register_device(void)
+static void tusb6010_register_types(void)
 {
     type_register_static(&tusb6010_info);
 }
 
-device_init(tusb6010_register_device)
+type_init(tusb6010_register_types)
diff --git a/hw/twl92230.c b/hw/twl92230.c
index 03fdccc..873dc8f 100644
--- a/hw/twl92230.c
+++ b/hw/twl92230.c
@@ -876,9 +876,9 @@ static TypeInfo twl92230_info = {
     .class_init    = twl92230_class_init,
 };
 
-static void twl92230_register_devices(void)
+static void twl92230_register_types(void)
 {
     type_register_static(&twl92230_info);
 }
 
-device_init(twl92230_register_devices)
+type_init(twl92230_register_types)
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 17d86aa..409bcd4 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -467,7 +467,7 @@ static TypeInfo pci_unin_internal_info = {
     .class_init    = pci_unin_internal_class_init,
 };
 
-static void unin_register_devices(void)
+static void unin_register_types(void)
 {
     type_register_static(&unin_main_pci_host_info);
     type_register_static(&u3_agp_pci_host_info);
@@ -480,4 +480,4 @@ static void unin_register_devices(void)
     type_register_static(&pci_unin_internal_info);
 }
 
-device_init(unin_register_devices)
+type_init(unin_register_types)
diff --git a/hw/usb-audio.c b/hw/usb-audio.c
index cd589b7..0cdfd91 100644
--- a/hw/usb-audio.c
+++ b/hw/usb-audio.c
@@ -706,10 +706,10 @@ static TypeInfo usb_audio_info = {
     .class_init    = usb_audio_class_init,
 };
 
-static void usb_audio_register_devices(void)
+static void usb_audio_register_types(void)
 {
     type_register_static(&usb_audio_info);
     usb_legacy_register("usb-audio", "audio", NULL);
 }
 
-device_init(usb_audio_register_devices)
+type_init(usb_audio_register_types)
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index 90c3b0e..a836de3 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -550,8 +550,9 @@ static TypeInfo bt_info = {
     .class_init    = usb_bt_class_initfn,
 };
 
-static void usb_bt_register_devices(void)
+static void usb_bt_register_types(void)
 {
     type_register_static(&bt_info);
 }
-device_init(usb_bt_register_devices)
+
+type_init(usb_bt_register_types)
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index b753834..e97fb6a 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -586,9 +586,9 @@ static TypeInfo usb_device_type_info = {
     .class_init = usb_device_class_init,
 };
 
-static void usb_register_devices(void)
+static void usb_register_types(void)
 {
     type_register_static(&usb_device_type_info);
 }
 
-device_init(usb_register_devices);
+type_init(usb_register_types)
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index 881da30..893d0a0 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -1354,10 +1354,11 @@ static TypeInfo ccid_card_type_info = {
     .class_init = ccid_card_class_init,
 };
 
-static void ccid_register_devices(void)
+static void ccid_register_types(void)
 {
     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)
+
+type_init(ccid_register_types)
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 75ef71e..4395ca2 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -2376,12 +2376,13 @@ static int usb_ehci_initfn(PCIDevice *dev)
     return 0;
 }
 
-static void ehci_register(void)
+static void ehci_register_types(void)
 {
     type_register_static(&ehci_info);
     type_register_static(&ich9_ehci_info);
 }
-device_init(ehci_register);
+
+type_init(ehci_register_types)
 
 /*
  * vim: expandtab ts=4
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 3c4e45d..8820abd 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -621,7 +621,7 @@ static TypeInfo usb_keyboard_info = {
     .class_init    = usb_keyboard_class_initfn,
 };
 
-static void usb_hid_register_devices(void)
+static void usb_hid_register_types(void)
 {
     type_register_static(&usb_tablet_info);
     usb_legacy_register("usb-tablet", "tablet", NULL);
@@ -630,4 +630,5 @@ static void usb_hid_register_devices(void)
     type_register_static(&usb_keyboard_info);
     usb_legacy_register("usb-kbd", "keyboard", NULL);
 }
-device_init(usb_hid_register_devices)
+
+type_init(usb_hid_register_types)
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 956b020..7604730 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -557,8 +557,9 @@ static TypeInfo hub_info = {
     .class_init    = usb_hub_class_initfn,
 };
 
-static void usb_hub_register_devices(void)
+static void usb_hub_register_types(void)
 {
     type_register_static(&hub_info);
 }
-device_init(usb_hub_register_devices)
+
+type_init(usb_hub_register_types)
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 6153376..5ed009d 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -669,9 +669,10 @@ static TypeInfo msd_info = {
     .class_init    = usb_msd_class_initfn,
 };
 
-static void usb_msd_register_devices(void)
+static void usb_msd_register_types(void)
 {
     type_register_static(&msd_info);
     usb_legacy_register("usb-storage", "disk", usb_msd_init);
 }
-device_init(usb_msd_register_devices)
+
+type_init(usb_msd_register_types)
diff --git a/hw/usb-net.c b/hw/usb-net.c
index e211141..77e3278 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1415,9 +1415,10 @@ static TypeInfo net_info = {
     .class_init    = usb_net_class_initfn,
 };
 
-static void usb_net_register_devices(void)
+static void usb_net_register_types(void)
 {
     type_register_static(&net_info);
     usb_legacy_register("usb-net", "net", usb_net_init);
 }
-device_init(usb_net_register_devices)
+
+type_init(usb_net_register_types)
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 425030f..da04c63 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1886,9 +1886,10 @@ static TypeInfo ohci_sysbus_info = {
     .class_init    = ohci_sysbus_class_init,
 };
 
-static void ohci_register(void)
+static void ohci_register_types(void)
 {
     type_register_static(&ohci_pci_info);
     type_register_static(&ohci_sysbus_info);
 }
-device_init(ohci_register);
+
+type_init(ohci_register_types)
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index c2cb6d2..f726a0a 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -628,11 +628,12 @@ static TypeInfo braille_info = {
     .class_init    = usb_braille_class_initfn,
 };
 
-static void usb_serial_register_devices(void)
+static void usb_serial_register_types(void)
 {
     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)
+
+type_init(usb_serial_register_types)
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index cddcc89..6f6ebf1 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -1321,7 +1321,7 @@ static TypeInfo ich9_uhci3_info = {
     .class_init    = ich9_uhci3_class_init,
 };
 
-static void uhci_register(void)
+static void uhci_register_types(void)
 {
     type_register_static(&piix3_uhci_info);
     type_register_static(&piix4_uhci_info);
@@ -1330,7 +1330,8 @@ static void uhci_register(void)
     type_register_static(&ich9_uhci2_info);
     type_register_static(&ich9_uhci3_info);
 }
-device_init(uhci_register);
+
+type_init(uhci_register_types)
 
 void usb_uhci_piix3_init(PCIBus *bus, int devfn)
 {
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 14de14d..6504e5e 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -373,9 +373,10 @@ static TypeInfo wacom_info = {
     .class_init    = usb_wacom_class_init,
 };
 
-static void usb_wacom_register_devices(void)
+static void usb_wacom_register_types(void)
 {
     type_register_static(&wacom_info);
     usb_legacy_register("usb-wacom-tablet", "wacom-tablet", NULL);
 }
-device_init(usb_wacom_register_devices)
+
+type_init(usb_wacom_register_types)
diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c
index 37e887c..750531f 100644
--- a/hw/usb-xhci.c
+++ b/hw/usb-xhci.c
@@ -2752,8 +2752,9 @@ static TypeInfo xhci_info = {
     .class_init    = xhci_class_init,
 };
 
-static void xhci_register(void)
+static void xhci_register_types(void)
 {
     type_register_static(&xhci_info);
 }
-device_init(xhci_register);
+
+type_init(xhci_register_types)
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index c4105e9..ae53a8b 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -154,11 +154,11 @@ static TypeInfo pci_realview_info = {
     .class_init    = pci_realview_class_init,
 };
 
-static void versatile_pci_register_devices(void)
+static void versatile_pci_register_types(void)
 {
     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)
+type_init(versatile_pci_register_types)
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 6ea0ce5..1903db6 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -382,9 +382,9 @@ static TypeInfo vpb_sic_info = {
     .class_init    = vpb_sic_class_init,
 };
 
-static void versatilepb_register_devices(void)
+static void versatilepb_register_types(void)
 {
     type_register_static(&vpb_sic_info);
 }
 
-device_init(versatilepb_register_devices)
+type_init(versatilepb_register_types)
diff --git a/hw/vga-isa.c b/hw/vga-isa.c
index 8d3ff0d..4bcc4db 100644
--- a/hw/vga-isa.c
+++ b/hw/vga-isa.c
@@ -85,8 +85,9 @@ static TypeInfo vga_info = {
     .class_init    = vga_class_initfn,
 };
 
-static void vga_register(void)
+static void vga_register_types(void)
 {
     type_register_static(&vga_info);
 }
-device_init(vga_register)
+
+type_init(vga_register_types)
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index 974a7a9..465b643 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -96,8 +96,9 @@ static TypeInfo vga_info = {
     .class_init    = vga_class_init,
 };
 
-static void vga_register(void)
+static void vga_register_types(void)
 {
     type_register_static(&vga_info);
 }
-device_init(vga_register);
+
+type_init(vga_register_types)
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index 4f2c3e4..cffee3d 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -149,12 +149,6 @@ static TypeInfo virtconsole_info = {
     .class_init    = virtconsole_class_init,
 };
 
-static void virtconsole_register(void)
-{
-    type_register_static(&virtconsole_info);
-}
-device_init(virtconsole_register)
-
 static Property virtserialport_properties[] = {
     DEFINE_PROP_CHR("chardev", VirtConsole, chr),
     DEFINE_PROP_END_OF_LIST(),
@@ -179,8 +173,10 @@ static TypeInfo virtserialport_info = {
     .class_init    = virtserialport_class_init,
 };
 
-static void virtserialport_register(void)
+static void virtconsole_register_types(void)
 {
+    type_register_static(&virtconsole_info);
     type_register_static(&virtserialport_info);
 }
-device_init(virtserialport_register)
+
+type_init(virtconsole_register_types)
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 93fff54..907b52a 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -930,7 +930,7 @@ static TypeInfo virtio_balloon_info = {
     .class_init    = virtio_balloon_class_init,
 };
 
-static void virtio_pci_register_devices(void)
+static void virtio_pci_register_types(void)
 {
     type_register_static(&virtio_blk_info);
     type_register_static(&virtio_net_info);
@@ -938,4 +938,4 @@ static void virtio_pci_register_devices(void)
     type_register_static(&virtio_balloon_info);
 }
 
-device_init(virtio_pci_register_devices)
+type_init(virtio_pci_register_types)
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 6117629..e22940e 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -949,9 +949,9 @@ static TypeInfo virtio_serial_port_type_info = {
     .class_init = virtio_serial_port_class_init,
 };
 
-static void virtio_serial_register_devices(void)
+static void virtio_serial_register_types(void)
 {
     type_register_static(&virtio_serial_port_type_info);
 }
 
-device_init(virtio_serial_register_devices);
+type_init(virtio_serial_register_types)
diff --git a/hw/vmmouse.c b/hw/vmmouse.c
index fda4f89..6338efa 100644
--- a/hw/vmmouse.c
+++ b/hw/vmmouse.c
@@ -294,8 +294,9 @@ static TypeInfo vmmouse_info = {
     .class_init    = vmmouse_class_initfn,
 };
 
-static void vmmouse_dev_register(void)
+static void vmmouse_register_types(void)
 {
     type_register_static(&vmmouse_info);
 }
-device_init(vmmouse_dev_register)
+
+type_init(vmmouse_register_types)
diff --git a/hw/vmport.c b/hw/vmport.c
index a2c45e1..9373be9 100644
--- a/hw/vmport.c
+++ b/hw/vmport.c
@@ -159,8 +159,9 @@ static TypeInfo vmport_info = {
     .class_init    = vmport_class_initfn,
 };
 
-static void vmport_dev_register(void)
+static void vmport_register_types(void)
 {
     type_register_static(&vmport_info);
 }
-device_init(vmport_dev_register)
+
+type_init(vmport_register_types)
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 3f3eb21..f8afa3c 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1223,8 +1223,9 @@ static TypeInfo vmsvga_info = {
     .class_init    = vmsvga_class_init,
 };
 
-static void vmsvga_register(void)
+static void vmsvga_register_types(void)
 {
     type_register_static(&vmsvga_info);
 }
-device_init(vmsvga_register);
+
+type_init(vmsvga_register_types)
diff --git a/hw/vt82c686.c b/hw/vt82c686.c
index aa0954f..fbab0bb 100644
--- a/hw/vt82c686.c
+++ b/hw/vt82c686.c
@@ -366,13 +366,6 @@ static TypeInfo via_ac97_info = {
     .class_init    = via_ac97_class_init,
 };
 
-static void vt82c686b_ac97_register(void)
-{
-    type_register_static(&via_ac97_info);
-}
-
-device_init(vt82c686b_ac97_register);
-
 static int vt82c686b_mc97_initfn(PCIDevice *dev)
 {
     VT686MC97State *s = DO_UPCAST(VT686MC97State, dev, dev);
@@ -414,13 +407,6 @@ static TypeInfo via_mc97_info = {
     .class_init    = via_mc97_class_init,
 };
 
-static void vt82c686b_mc97_register(void)
-{
-    type_register_static(&via_mc97_info);
-}
-
-device_init(vt82c686b_mc97_register);
-
 /* vt82c686 pm init */
 static int vt82c686b_pm_initfn(PCIDevice *dev)
 {
@@ -497,13 +483,6 @@ static TypeInfo via_pm_info = {
     .class_init    = via_pm_class_init,
 };
 
-static void vt82c686b_pm_register(void)
-{
-    type_register_static(&via_pm_info);
-}
-
-device_init(vt82c686b_pm_register);
-
 static const VMStateDescription vmstate_via = {
     .name = "vt82c686b",
     .version_id = 1,
@@ -571,8 +550,12 @@ static TypeInfo via_info = {
     .class_init    = via_class_init,
 };
 
-static void vt82c686b_register(void)
+static void vt82c686b_register_types(void)
 {
+    type_register_static(&via_ac97_info);
+    type_register_static(&via_mc97_info);
+    type_register_static(&via_pm_info);
     type_register_static(&via_info);
 }
-device_init(vt82c686b_register);
+
+type_init(vt82c686b_register_types)
diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
index 41325f0..15c69db 100644
--- a/hw/wdt_i6300esb.c
+++ b/hw/wdt_i6300esb.c
@@ -448,10 +448,10 @@ static TypeInfo i6300esb_info = {
     .class_init    = i6300esb_class_init,
 };
 
-static void i6300esb_register_devices(void)
+static void i6300esb_register_types(void)
 {
     watchdog_add_model(&model);
     type_register_static(&i6300esb_info);
 }
 
-device_init(i6300esb_register_devices);
+type_init(i6300esb_register_types)
diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c
index 8faa231..7f6c21d 100644
--- a/hw/wdt_ib700.c
+++ b/hw/wdt_ib700.c
@@ -136,10 +136,10 @@ static TypeInfo wdt_ib700_info = {
     .class_init    = wdt_ib700_class_init,
 };
 
-static void wdt_ib700_register_devices(void)
+static void wdt_ib700_register_types(void)
 {
     watchdog_add_model(&model);
     type_register_static(&wdt_ib700_info);
 }
 
-device_init(wdt_ib700_register_devices);
+type_init(wdt_ib700_register_types)
diff --git a/hw/wm8750.c b/hw/wm8750.c
index 18afa4c..11bcec3 100644
--- a/hw/wm8750.c
+++ b/hw/wm8750.c
@@ -708,9 +708,9 @@ static TypeInfo wm8750_info = {
     .class_init    = wm8750_class_init,
 };
 
-static void wm8750_register_devices(void)
+static void wm8750_register_types(void)
 {
     type_register_static(&wm8750_info);
 }
 
-device_init(wm8750_register_devices)
+type_init(wm8750_register_types)
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
index e757102..5a7c4cc 100644
--- a/hw/xen_platform.c
+++ b/hw/xen_platform.c
@@ -396,9 +396,9 @@ static TypeInfo xen_platform_info = {
     .class_init    = xen_platform_class_init,
 };
 
-static void xen_platform_register(void)
+static void xen_platform_register_types(void)
 {
     type_register_static(&xen_platform_info);
 }
 
-device_init(xen_platform_register);
+type_init(xen_platform_register_types)
diff --git a/hw/xgmac.c b/hw/xgmac.c
index d395b1c..dd4bdc4 100644
--- a/hw/xgmac.c
+++ b/hw/xgmac.c
@@ -425,9 +425,9 @@ static TypeInfo xgmac_enet_info = {
     .class_init    = xgmac_enet_class_init,
 };
 
-static void xgmac_enet_register(void)
+static void xgmac_enet_register_types(void)
 {
     type_register_static(&xgmac_enet_info);
 }
 
-device_init(xgmac_enet_register)
+type_init(xgmac_enet_register_types)
diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c
index e8a5312..85dfcbf 100644
--- a/hw/xilinx_axidma.c
+++ b/hw/xilinx_axidma.c
@@ -508,9 +508,9 @@ static TypeInfo axidma_info = {
     .class_init    = axidma_class_init,
 };
 
-static void xilinx_axidma_register(void)
+static void xilinx_axidma_register_types(void)
 {
     type_register_static(&axidma_info);
 }
 
-device_init(xilinx_axidma_register)
+type_init(xilinx_axidma_register_types)
diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
index 1ce2db4..7526273 100644
--- a/hw/xilinx_axienet.c
+++ b/hw/xilinx_axienet.c
@@ -894,9 +894,10 @@ static TypeInfo xilinx_enet_info = {
     .instance_size = sizeof(struct XilinxAXIEnet),
     .class_init    = xilinx_enet_class_init,
 };
-static void xilinx_enet_register(void)
+
+static void xilinx_enet_register_types(void)
 {
     type_register_static(&xilinx_enet_info);
 }
 
-device_init(xilinx_enet_register)
+type_init(xilinx_enet_register_types)
diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c
index 499feef..857b33d 100644
--- a/hw/xilinx_ethlite.c
+++ b/hw/xilinx_ethlite.c
@@ -249,9 +249,9 @@ static TypeInfo xilinx_ethlite_info = {
     .class_init    = xilinx_ethlite_class_init,
 };
 
-static void xilinx_ethlite_register(void)
+static void xilinx_ethlite_register_types(void)
 {
     type_register_static(&xilinx_ethlite_info);
 }
 
-device_init(xilinx_ethlite_register)
+type_init(xilinx_ethlite_register_types)
diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c
index 73eed6d..553f848 100644
--- a/hw/xilinx_intc.c
+++ b/hw/xilinx_intc.c
@@ -182,9 +182,9 @@ static TypeInfo xilinx_intc_info = {
     .class_init    = xilinx_intc_class_init,
 };
 
-static void xilinx_intc_register(void)
+static void xilinx_intc_register_types(void)
 {
     type_register_static(&xilinx_intc_info);
 }
 
-device_init(xilinx_intc_register)
+type_init(xilinx_intc_register_types)
diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c
index c8236d2..3ab2f2b 100644
--- a/hw/xilinx_timer.c
+++ b/hw/xilinx_timer.c
@@ -241,9 +241,9 @@ static TypeInfo xilinx_timer_info = {
     .class_init    = xilinx_timer_class_init,
 };
 
-static void xilinx_timer_register(void)
+static void xilinx_timer_register_types(void)
 {
     type_register_static(&xilinx_timer_info);
 }
 
-device_init(xilinx_timer_register)
+type_init(xilinx_timer_register_types)
diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c
index 1c2b908..aa0170d 100644
--- a/hw/xilinx_uartlite.c
+++ b/hw/xilinx_uartlite.c
@@ -225,9 +225,9 @@ static TypeInfo xilinx_uartlite_info = {
     .class_init    = xilinx_uartlite_class_init,
 };
 
-static void xilinx_uart_register(void)
+static void xilinx_uart_register_types(void)
 {
     type_register_static(&xilinx_uartlite_info);
 }
 
-device_init(xilinx_uart_register)
+type_init(xilinx_uart_register_types)
diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c
index 07e4fc1..319624f 100644
--- a/hw/xio3130_downstream.c
+++ b/hw/xio3130_downstream.c
@@ -203,12 +203,12 @@ static TypeInfo xio3130_downstream_info = {
     .class_init    = xio3130_downstream_class_init,
 };
 
-static void xio3130_downstream_register(void)
+static void xio3130_downstream_register_types(void)
 {
     type_register_static(&xio3130_downstream_info);
 }
 
-device_init(xio3130_downstream_register);
+type_init(xio3130_downstream_register_types)
 
 /*
  * Local variables:
diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c
index 7887c92..34a99bb 100644
--- a/hw/xio3130_upstream.c
+++ b/hw/xio3130_upstream.c
@@ -177,12 +177,12 @@ static TypeInfo xio3130_upstream_info = {
     .class_init    = xio3130_upstream_class_init,
 };
 
-static void xio3130_upstream_register(void)
+static void xio3130_upstream_register_types(void)
 {
     type_register_static(&xio3130_upstream_info);
 }
 
-device_init(xio3130_upstream_register);
+type_init(xio3130_upstream_register_types)
 
 
 /*
diff --git a/hw/zaurus.c b/hw/zaurus.c
index 055df9b..72838ec 100644
--- a/hw/zaurus.c
+++ b/hw/zaurus.c
@@ -243,11 +243,12 @@ static TypeInfo scoop_sysbus_info = {
     .class_init    = scoop_sysbus_class_init,
 };
 
-static void scoop_register(void)
+static void scoop_register_types(void)
 {
     type_register_static(&scoop_sysbus_info);
 }
-device_init(scoop_register);
+
+type_init(scoop_register_types)
 
 /* Write the bootloader parameters memory area.  */
 
diff --git a/include/qemu/object.h b/include/qemu/object.h
index 7d50da9..69cc2ab 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -71,12 +71,12 @@ typedef struct InterfaceInfo InterfaceInfo;
  *     .instance_size = sizeof(MyDevice),
  * };
  *
- * static void my_device_module_init(void)
+ * static void my_device_register_types(void)
  * {
  *     type_register_static(&my_device_info);
  * }
  *
- * device_init(my_device_module_init);
+ * type_init(my_device_register_types)
  *   </programlisting>
  * </example>
  *
diff --git a/module.h b/module.h
index ef66730..c4ccd57 100644
--- a/module.h
+++ b/module.h
@@ -22,16 +22,16 @@ static void __attribute__((constructor)) do_qemu_init_ ## function(void) {  \
 
 typedef enum {
     MODULE_INIT_BLOCK,
-    MODULE_INIT_DEVICE,
     MODULE_INIT_MACHINE,
     MODULE_INIT_QAPI,
+    MODULE_INIT_QOM,
     MODULE_INIT_MAX
 } module_init_type;
 
 #define block_init(function) module_init(function, MODULE_INIT_BLOCK)
-#define device_init(function) module_init(function, MODULE_INIT_DEVICE)
 #define machine_init(function) module_init(function, MODULE_INIT_MACHINE)
 #define qapi_init(function) module_init(function, MODULE_INIT_QAPI)
+#define type_init(function) module_init(function, MODULE_INIT_QOM)
 
 void register_module_init(void (*fn)(void), module_init_type type);
 
diff --git a/qom/container.c b/qom/container.c
index 946cbff..f107208 100644
--- a/qom/container.c
+++ b/qom/container.c
@@ -19,9 +19,9 @@ static TypeInfo container_info = {
     .parent        = TYPE_OBJECT,
 };
 
-static void container_init(void)
+static void container_register_types(void)
 {
     type_register_static(&container_info);
 }
 
-device_init(container_init);
+type_init(container_register_types)
diff --git a/qom/object.c b/qom/object.c
index 5e5b261..0cbd9bb 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -444,7 +444,7 @@ Object *object_dynamic_cast(Object *obj, const char *typename)
 }
 
 
-static void register_interface(void)
+static void register_types(void)
 {
     static TypeInfo interface_info = {
         .name = TYPE_INTERFACE,
@@ -455,7 +455,7 @@ static void register_interface(void)
     type_interface = type_register_static(&interface_info);
 }
 
-device_init(register_interface);
+type_init(register_types)
 
 Object *object_dynamic_cast_assert(Object *obj, const char *typename)
 {
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 5639c6f..b4629f8 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -753,8 +753,9 @@ static void spice_register_config(void)
 }
 machine_init(spice_register_config);
 
-static void spice_initialize(void)
+static void spice_register_types(void)
 {
     qemu_spice_init();
 }
-device_init(spice_initialize);
+
+type_init(spice_register_types)
diff --git a/usb-bsd.c b/usb-bsd.c
index fc722b3..0fd12a2 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -417,11 +417,12 @@ static TypeInfo usb_host_dev_info = {
     .class_init    = usb_host_class_initfn,
 };
 
-static void usb_host_register_devices(void)
+static void usb_host_register_types(void)
 {
     type_register_static(&usb_host_dev_info);
 }
-device_init(usb_host_register_devices)
+
+type_init(usb_host_register_types)
 
 static int usb_host_scan(void *opaque, USBScanFunc *func)
 {
diff --git a/usb-linux.c b/usb-linux.c
index e7fc9ec..5e95be6 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -1436,12 +1436,13 @@ static TypeInfo usb_host_dev_info = {
     .class_init    = usb_host_class_initfn,
 };
 
-static void usb_host_register_devices(void)
+static void usb_host_register_types(void)
 {
     type_register_static(&usb_host_dev_info);
     usb_legacy_register("usb-host", "host", usb_host_device_open);
 }
-device_init(usb_host_register_devices)
+
+type_init(usb_host_register_types)
 
 USBDevice *usb_host_device_open(const char *devname)
 {
diff --git a/usb-redir.c b/usb-redir.c
index 303292a..82e7e21 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -1344,8 +1344,9 @@ static TypeInfo usbredir_dev_info = {
     .class_init    = usbredir_class_initfn,
 };
 
-static void usbredir_register_devices(void)
+static void usbredir_register_types(void)
 {
     type_register_static(&usbredir_dev_info);
 }
-device_init(usbredir_register_devices);
+
+type_init(usbredir_register_types)
diff --git a/vl.c b/vl.c
index 63dd725..9b7ddfe 100644
--- a/vl.c
+++ b/vl.c
@@ -3361,7 +3361,7 @@ int main(int argc, char **argv, char **envp)
     if (foreach_device_config(DEV_DEBUGCON, debugcon_parse) < 0)
         exit(1);
 
-    module_call_init(MODULE_INIT_DEVICE);
+    module_call_init(MODULE_INIT_QOM);
 
     /* must be after qdev registration but before machine init */
     if (vga_model) {
commit 59f971d451fbabee3194bb565f40846398ee6e6f
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Feb 14 10:19:53 2012 +0100

    qdev: print error message before aborting
    
    qdev_prop_set_* functions are always called by machine init functions
    that should know what they're doing, so they abort on error.  Still,
    an assert(!errp) does not aid debugging.  Print an error before aborting.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 6f09a35..7b74dd5 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -1072,49 +1072,49 @@ void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
 {
     Error *errp = NULL;
     object_property_set_bool(OBJECT(dev), value, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value)
 {
     Error *errp = NULL;
     object_property_set_int(OBJECT(dev), value, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value)
 {
     Error *errp = NULL;
     object_property_set_int(OBJECT(dev), value, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value)
 {
     Error *errp = NULL;
     object_property_set_int(OBJECT(dev), value, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value)
 {
     Error *errp = NULL;
     object_property_set_int(OBJECT(dev), value, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value)
 {
     Error *errp = NULL;
     object_property_set_int(OBJECT(dev), value, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_string(DeviceState *dev, const char *name, char *value)
 {
     Error *errp = NULL;
     object_property_set_str(OBJECT(dev), value, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value)
@@ -1143,7 +1143,7 @@ void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *valu
     assert(!value || value->label);
     object_property_set_str(OBJECT(dev),
                             value ? value->label : "", name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_netdev(DeviceState *dev, const char *name, VLANClientState *value)
@@ -1152,14 +1152,14 @@ void qdev_prop_set_netdev(DeviceState *dev, const char *name, VLANClientState *v
     assert(!value || value->name);
     object_property_set_str(OBJECT(dev),
                             value ? value->name : "", name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value)
 {
     Error *errp = NULL;
     object_property_set_int(OBJECT(dev), value ? value->id : -1, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
@@ -1170,7 +1170,7 @@ void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
              value[0], value[1], value[2], value[3], value[4], value[5]);
 
     object_property_set_str(OBJECT(dev), str, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
@@ -1181,7 +1181,7 @@ void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
     prop = qdev_prop_find(dev, name);
     object_property_set_str(OBJECT(dev), prop->info->enum_table[value],
                             name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
@@ -1213,7 +1213,7 @@ void qdev_prop_set_defaults(DeviceState *dev, Property *props)
         } else if (props->qtype == QTYPE_QINT) {
             object_property_set_int(obj, props->defval, props->name, &errp);
         }
-        assert(!errp);
+        assert_no_error(errp);
     }
 }
 
diff --git a/qerror.c b/qerror.c
index 8e6efaf..f55d435 100644
--- a/qerror.c
+++ b/qerror.c
@@ -572,6 +572,14 @@ void qerror_report_err(Error *err)
     }
 }
 
+void assert_no_error(Error *err)
+{
+    if (err) {
+        qerror_report_err(err);
+        abort();
+    }
+}
+
 /**
  * qobject_to_qerror(): Convert a QObject into a QError
  */
diff --git a/qerror.h b/qerror.h
index e8718bf..e26c635 100644
--- a/qerror.h
+++ b/qerror.h
@@ -41,6 +41,7 @@ void qerror_print(QError *qerror);
 void qerror_report_internal(const char *file, int linenr, const char *func,
                             const char *fmt, ...) GCC_FMT_ATTR(4, 5);
 void qerror_report_err(Error *err);
+void assert_no_error(Error *err);
 QString *qerror_format(const char *fmt, QDict *error);
 #define qerror_report(fmt, ...) \
     qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__)
commit 0a54a0ce3e7659d7804274fcb058154d52fb8d82
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Feb 14 10:19:52 2012 +0100

    qdev: allow setting properties to NULL
    
    SPARC and PPC set properties to NULL.  This can be done with an
    empty string value.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index b6d6fcf..6f09a35 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -613,7 +613,7 @@ static void set_pointer(Object *obj, Visitor *v, Property *prop,
     }
     if (!*str) {
         g_free(str);
-        error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
+        *ptr = NULL;
         return;
     }
     ret = parse(dev, str, ptr);
@@ -1120,7 +1120,8 @@ void qdev_prop_set_string(DeviceState *dev, const char *name, char *value)
 int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value)
 {
     Error *errp = NULL;
-    object_property_set_str(OBJECT(dev), bdrv_get_device_name(value),
+    const char *bdrv_name = value ? bdrv_get_device_name(value) : "";
+    object_property_set_str(OBJECT(dev), bdrv_name,
                             name, &errp);
     if (errp) {
         qerror_report_err(errp);
@@ -1139,16 +1140,18 @@ void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverS
 void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value)
 {
     Error *errp = NULL;
-    assert(value->label);
-    object_property_set_str(OBJECT(dev), value->label, name, &errp);
+    assert(!value || value->label);
+    object_property_set_str(OBJECT(dev),
+                            value ? value->label : "", name, &errp);
     assert(!errp);
 }
 
 void qdev_prop_set_netdev(DeviceState *dev, const char *name, VLANClientState *value)
 {
     Error *errp = NULL;
-    assert(value->name);
-    object_property_set_str(OBJECT(dev), value->name, name, &errp);
+    assert(!value || value->name);
+    object_property_set_str(OBJECT(dev),
+                            value ? value->name : "", name, &errp);
     assert(!errp);
 }
 
commit 9d4df9c02866f39d3eef105033091f367cc7c29e
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Feb 4 11:47:17 2012 +0000

    ppc: remove unused variables
    
    Fix this error:
    /src/qemu/target-ppc/helper.c: In function 'booke206_tlb_to_page_size':
    /src/qemu/target-ppc/helper.c:1296:14: error: variable 'tlbncfg' set but not used [-Werror=unused-but-set-variable]
    
    Tested-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index e56fac8..928fbcf 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1293,11 +1293,8 @@ void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot)
 
 target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb)
 {
-    uint32_t tlbncfg;
-    int tlbn = booke206_tlbm_to_tlbn(env, tlb);
     int tlbm_size;
 
-    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
     tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
 
     return 1024ULL << tlbm_size;
commit bda254daf8016ef474afb51122c5c2d6cfc3b80e
Author: Jan Kiszka <jan.kiszka at web.de>
Date:   Sat Feb 4 15:58:02 2012 +0100

    cfi02: Fix lazy ROMD switching - once again
    
    The conversion to memory regions broke lazy ROMD switching by forgetting
    to update the rom_mode state variable.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at web.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c
index a9e88b9..2ca0fd4 100644
--- a/hw/pflash_cfi02.c
+++ b/hw/pflash_cfi02.c
@@ -102,6 +102,7 @@ static void pflash_setup_mappings(pflash_t *pfl)
 static void pflash_register_memory(pflash_t *pfl, int rom_mode)
 {
     memory_region_rom_device_set_readable(&pfl->orig_mem, rom_mode);
+    pfl->rom_mode = rom_mode;
 }
 
 static void pflash_timer (void *opaque)
commit 4896d74b844b1845de32c29743fe09e4145f0601
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Feb 4 16:25:42 2012 +0100

    memory-region: Report if region is read-only or write-only on info mtree
    
    Helpful to understand guest configurations of things like the i440FX's
    PAM or the state of ROM devices.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/memory.c b/memory.c
index 5e77d8a..22816e2 100644
--- a/memory.c
+++ b/memory.c
@@ -1609,23 +1609,31 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f,
             ml->printed = false;
             QTAILQ_INSERT_TAIL(alias_print_queue, ml, queue);
         }
-        mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d): alias %s @%s "
-                   TARGET_FMT_plx "-" TARGET_FMT_plx "\n",
+        mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx
+                   " (prio %d, %c%c): alias %s @%s " TARGET_FMT_plx
+                   "-" TARGET_FMT_plx "\n",
                    base + mr->addr,
                    base + mr->addr
                    + (target_phys_addr_t)int128_get64(mr->size) - 1,
                    mr->priority,
+                   mr->readable ? 'R' : '-',
+                   !mr->readonly && !(mr->rom_device && mr->readable) ? 'W'
+                                                                      : '-',
                    mr->name,
                    mr->alias->name,
                    mr->alias_offset,
                    mr->alias_offset
                    + (target_phys_addr_t)int128_get64(mr->size) - 1);
     } else {
-        mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d): %s\n",
+        mon_printf(f,
+                   TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d, %c%c): %s\n",
                    base + mr->addr,
                    base + mr->addr
                    + (target_phys_addr_t)int128_get64(mr->size) - 1,
                    mr->priority,
+                   mr->readable ? 'R' : '-',
+                   !mr->readonly && !(mr->rom_device && mr->readable) ? 'W'
+                                                                      : '-',
                    mr->name);
     }
 
commit 734781c9a03745a28fba3e538d33d4e39c5e4ff5
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Feb 7 16:03:24 2012 +0100

    vga: Fix full updates in graphic mode
    
    This fixes the regression introduced by cd7a45c95e: We lost the or'ing
    with the full_update flag.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/vga.c b/hw/vga.c
index d27700d..c1029db 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1777,10 +1777,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
         if (!(s->cr[VGA_CRTC_MODE] & 2)) {
             addr = (addr & ~0x8000) | ((y1 & 2) << 14);
         }
+        update = full_update;
         page0 = addr;
         page1 = addr + bwidth - 1;
-        update = memory_region_get_dirty(&s->vram, page0, page1 - page0,
-                                         DIRTY_MEMORY_VGA);
+        update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
+                                          DIRTY_MEMORY_VGA);
         /* explicit invalidation for the hardware cursor */
         update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
         if (update) {
commit d1f3dd343c163d0e1d188b964b7d635692bac7d8
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Feb 4 17:09:14 2012 +0000

    Fix memory dirty getting API change fallout
    
    Fix confusion in length calculation in commit
    cd7a45c95ecf2404810f3c6becb7cb83c5010ad8.
    
    Reported-by: Jan Kiszka <jan.kiszka at web.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/framebuffer.c b/hw/framebuffer.c
index ea122fb..f4747cd 100644
--- a/hw/framebuffer.c
+++ b/hw/framebuffer.c
@@ -87,7 +87,7 @@ void framebuffer_update_display(
     dest += i * dest_row_pitch;
 
     for (; i < rows; i++) {
-        dirty = memory_region_get_dirty(mem, addr, addr + src_width,
+        dirty = memory_region_get_dirty(mem, addr, src_width,
                                              DIRTY_MEMORY_VGA);
         if (dirty || invalidate) {
             fn(opaque, dest, src, cols, dest_col_pitch);
diff --git a/hw/sm501.c b/hw/sm501.c
index 94c0abf..786e076 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -1327,8 +1327,8 @@ static void sm501_draw_crt(SM501State * s)
         ram_addr_t page1 = offset + width * src_bpp - 1;
 
 	/* check dirty flags for each line */
-        update = memory_region_get_dirty(&s->local_mem_region, page0, page1,
-                                         DIRTY_MEMORY_VGA);
+        update = memory_region_get_dirty(&s->local_mem_region, page0,
+                                         page1 - page0, DIRTY_MEMORY_VGA);
 
 	/* draw line and change status */
 	if (update) {
diff --git a/hw/vga.c b/hw/vga.c
index d87c4f9..d27700d 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1779,7 +1779,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
         }
         page0 = addr;
         page1 = addr + bwidth - 1;
-        update = memory_region_get_dirty(&s->vram, page0, page1,
+        update = memory_region_get_dirty(&s->vram, page0, page1 - page0,
                                          DIRTY_MEMORY_VGA);
         /* explicit invalidation for the hardware cursor */
         update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
commit 7c605a23b2c7606f5f06b7d83d8927b1dc111478
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jan 20 13:29:16 2012 +0100

    xhci: handle USB_RET_NAK
    
    Add a field to XHCITransfer to correctly keep track of NAK'ed usb
    packets.  Retry transfers when the endpoint is kicked again.  Implement
    wakeup_endpoint bus op so we can kick the endpoint when needed.
    
    With this patch applied the emulated hid devices are working correctly
    when hooked up to xhci.  usb-tabled without polling, yay!
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c
index 3026edb..ac7b12b 100644
--- a/hw/usb-xhci.c
+++ b/hw/usb-xhci.c
@@ -307,7 +307,8 @@ typedef struct XHCIState XHCIState;
 typedef struct XHCITransfer {
     XHCIState *xhci;
     USBPacket packet;
-    bool running;
+    bool running_async;
+    bool running_retry;
     bool cancelled;
     bool complete;
     bool backgrounded;
@@ -338,6 +339,7 @@ typedef struct XHCIEPContext {
     unsigned int next_xfer;
     unsigned int comp_xfer;
     XHCITransfer transfers[TD_QUEUE];
+    XHCITransfer *retry;
     bool bg_running;
     bool bg_updating;
     unsigned int next_bg;
@@ -915,12 +917,17 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
     xferi = epctx->next_xfer;
     for (i = 0; i < TD_QUEUE; i++) {
         XHCITransfer *t = &epctx->transfers[xferi];
-        if (t->running) {
+        if (t->running_async) {
+            usb_cancel_packet(&t->packet);
+            t->running_async = 0;
             t->cancelled = 1;
-            /* libusb_cancel_transfer(t->usbxfer) */
             DPRINTF("xhci: cancelling transfer %d, waiting for it to complete...\n", i);
             killed++;
         }
+        if (t->running_retry) {
+            t->running_retry = 0;
+            epctx->retry = NULL;
+        }
         if (t->backgrounded) {
             t->backgrounded = 0;
         }
@@ -941,9 +948,10 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
         xferi = epctx->next_bg;
         for (i = 0; i < BG_XFERS; i++) {
             XHCITransfer *t = &epctx->bg_transfers[xferi];
-            if (t->running) {
+            if (t->running_async) {
+                usb_cancel_packet(&t->packet);
+                t->running_async = 0;
                 t->cancelled = 1;
-                /* libusb_cancel_transfer(t->usbxfer); */
                 DPRINTF("xhci: cancelling bg transfer %d, waiting for it to complete...\n", i);
                 killed++;
             }
@@ -1409,12 +1417,20 @@ static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev)
 static int xhci_complete_packet(XHCITransfer *xfer, int ret)
 {
     if (ret == USB_RET_ASYNC) {
-        xfer->running = 1;
+        xfer->running_async = 1;
+        xfer->running_retry = 0;
+        xfer->complete = 0;
+        xfer->cancelled = 0;
+        return 0;
+    } else if (ret == USB_RET_NAK) {
+        xfer->running_async = 0;
+        xfer->running_retry = 1;
         xfer->complete = 0;
         xfer->cancelled = 0;
         return 0;
     } else {
-        xfer->running = 0;
+        xfer->running_async = 0;
+        xfer->running_retry = 0;
         xfer->complete = 1;
     }
 
@@ -1529,7 +1545,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
                                     wValue, wIndex, wLength, xfer->data);
 
     xhci_complete_packet(xfer, ret);
-    if (!xfer->running) {
+    if (!xfer->running_async && !xfer->running_retry) {
         xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
     }
     return 0;
@@ -1596,7 +1612,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
     ret = usb_handle_packet(dev, &xfer->packet);
 
     xhci_complete_packet(xfer, ret);
-    if (!xfer->running) {
+    if (!xfer->running_async && !xfer->running_retry) {
         xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
     }
     return 0;
@@ -1667,6 +1683,25 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
         return;
     }
 
+    if (epctx->retry) {
+        /* retry nak'ed transfer */
+        XHCITransfer *xfer = epctx->retry;
+        int result;
+
+        DPRINTF("xhci: retry nack'ed transfer ...\n");
+        assert(xfer->running_retry);
+        xhci_setup_packet(xfer, xfer->packet.ep->dev);
+        result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
+        if (result == USB_RET_NAK) {
+            DPRINTF("xhci: ... xfer still nacked\n");
+            return;
+        }
+        DPRINTF("xhci: ... result %d\n", result);
+        xhci_complete_packet(xfer, result);
+        assert(!xfer->running_retry);
+        epctx->retry = NULL;
+    }
+
     if (epctx->state == EP_HALTED) {
         DPRINTF("xhci: ep halted, not running schedule\n");
         return;
@@ -1676,9 +1711,13 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
 
     while (1) {
         XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer];
-        if (xfer->running || xfer->backgrounded) {
-            DPRINTF("xhci: ep is busy\n");
+        if (xfer->running_async || xfer->running_retry || xfer->backgrounded) {
+            DPRINTF("xhci: ep is busy (#%d,%d,%d,%d)\n",
+                    epctx->next_xfer, xfer->running_async,
+                    xfer->running_retry, xfer->backgrounded);
             break;
+        } else {
+            DPRINTF("xhci: ep: using #%d\n", epctx->next_xfer);
         }
         length = xhci_ring_chain_length(xhci, &epctx->ring);
         if (length < 0) {
@@ -1725,6 +1764,11 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
             DPRINTF("xhci: ep halted, stopping schedule\n");
             break;
         }
+        if (xfer->running_retry) {
+            DPRINTF("xhci: xfer nacked, stopping schedule\n");
+            epctx->retry = xfer;
+            break;
+        }
 
         /*
          * Qemu usb can't handle multiple in-flight xfers.
@@ -2739,7 +2783,48 @@ static USBPortOps xhci_port_ops = {
     .child_detach = xhci_child_detach,
 };
 
+static int xhci_find_slotid(XHCIState *xhci, USBDevice *dev)
+{
+    XHCISlot *slot;
+    int slotid;
+
+    for (slotid = 1; slotid <= MAXSLOTS; slotid++) {
+        slot = &xhci->slots[slotid-1];
+        if (slot->devaddr == dev->addr) {
+            return slotid;
+        }
+    }
+    return 0;
+}
+
+static int xhci_find_epid(USBEndpoint *ep)
+{
+    if (ep->nr == 0) {
+        return 1;
+    }
+    if (ep->pid == USB_TOKEN_IN) {
+        return ep->nr * 2 + 1;
+    } else {
+        return ep->nr * 2;
+    }
+}
+
+static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep)
+{
+    XHCIState *xhci = container_of(bus, XHCIState, bus);
+    int slotid;
+
+    DPRINTF("%s\n", __func__);
+    slotid = xhci_find_slotid(xhci, ep->dev);
+    if (slotid == 0 || !xhci->slots[slotid-1].enabled) {
+        DPRINTF("%s: oops, no slot for dev %d\n", __func__, ep->dev->addr);
+        return;
+    }
+    xhci_kick_ep(xhci, slotid, xhci_find_epid(ep));
+}
+
 static USBBusOps xhci_bus_ops = {
+    .wakeup_endpoint = xhci_wakeup_endpoint,
 };
 
 static void usb_xhci_init(XHCIState *xhci, DeviceState *dev)
commit 8c735e431d384663137a709c8207f4ada3146205
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jan 20 17:09:58 2012 +0100

    xhci: remote wakeup support
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c
index 65214af..3026edb 100644
--- a/hw/usb-xhci.c
+++ b/hw/usb-xhci.c
@@ -2698,6 +2698,26 @@ static void xhci_detach(USBPort *usbport)
     xhci_update_port(xhci, port, 1);
 }
 
+static void xhci_wakeup(USBPort *usbport)
+{
+    XHCIState *xhci = usbport->opaque;
+    XHCIPort *port = &xhci->ports[usbport->index];
+    int nr = port->port.index + 1;
+    XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, nr << 24};
+    uint32_t pls;
+
+    pls = (port->portsc >> PORTSC_PLS_SHIFT) & PORTSC_PLS_MASK;
+    if (pls != 3) {
+        return;
+    }
+    port->portsc |= 0xf << PORTSC_PLS_SHIFT;
+    if (port->portsc & PORTSC_PLC) {
+        return;
+    }
+    port->portsc |= PORTSC_PLC;
+    xhci_event(xhci, &ev);
+}
+
 static void xhci_complete(USBPort *port, USBPacket *packet)
 {
     XHCITransfer *xfer = container_of(packet, XHCITransfer, packet);
@@ -2714,6 +2734,7 @@ static void xhci_child_detach(USBPort *port, USBDevice *child)
 static USBPortOps xhci_port_ops = {
     .attach   = xhci_attach,
     .detach   = xhci_detach,
+    .wakeup   = xhci_wakeup,
     .complete = xhci_complete,
     .child_detach = xhci_child_detach,
 };
commit b819d7169a8f026c7b9174b7cbce8ab50fc7908a
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jan 20 15:25:16 2012 +0100

    xhci: kill port arg from xhci_setup_packet
    
    Unused argument, remove it.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c
index 7682126..65214af 100644
--- a/hw/usb-xhci.c
+++ b/hw/usb-xhci.c
@@ -1392,7 +1392,7 @@ static int xhci_hle_control(XHCIState *xhci, XHCITransfer *xfer,
 }
 #endif
 
-static int xhci_setup_packet(XHCITransfer *xfer, XHCIPort *port, USBDevice *dev)
+static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev)
 {
     USBEndpoint *ep;
     int dir;
@@ -1520,7 +1520,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
     xfer->in_xfer = bmRequestType & USB_DIR_IN;
     xfer->iso_xfer = false;
 
-    xhci_setup_packet(xfer, port, dev);
+    xhci_setup_packet(xfer, dev);
     if (!xfer->in_xfer) {
         xhci_xfer_data(xfer, xfer->data, wLength, 0, 1, 0);
     }
@@ -1571,7 +1571,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
         return -1;
     }
 
-    xhci_setup_packet(xfer, port, dev);
+    xhci_setup_packet(xfer, dev);
 
     switch(epctx->type) {
     case ET_INTR_OUT:
commit 3c4866e07ed17c7d64c2fd30738f68276ca353d9
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jan 17 13:25:13 2012 +0100

    xhci: stop on errors
    
    When some error happened we'll have to stop processing the endpoint.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c
index 5e618f0..7682126 100644
--- a/hw/usb-xhci.c
+++ b/hw/usb-xhci.c
@@ -1721,10 +1721,14 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
             }
         }
 
+        if (epctx->state == EP_HALTED) {
+            DPRINTF("xhci: ep halted, stopping schedule\n");
+            break;
+        }
+
         /*
          * Qemu usb can't handle multiple in-flight xfers.
-         * Also xfers might be finished here already,
-         * possibly with an error.  Stop here for now.
+         * Stop here for now.
          */
         break;
     }
commit f10de44e7eb8304406d42a2a7242887c08282c4a
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jan 17 11:21:06 2012 +0100

    xhci: add trb type name lookup support.
    
    When logging TRBs add a the type name for more readable debug output.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c
index 27bdc2b..5e618f0 100644
--- a/hw/usb-xhci.c
+++ b/hw/usb-xhci.c
@@ -420,6 +420,60 @@ typedef struct XHCIEvRingSeg {
     uint32_t rsvd;
 } XHCIEvRingSeg;
 
+#ifdef DEBUG_XHCI
+static const char *TRBType_names[] = {
+    [TRB_RESERVED]                     = "TRB_RESERVED",
+    [TR_NORMAL]                        = "TR_NORMAL",
+    [TR_SETUP]                         = "TR_SETUP",
+    [TR_DATA]                          = "TR_DATA",
+    [TR_STATUS]                        = "TR_STATUS",
+    [TR_ISOCH]                         = "TR_ISOCH",
+    [TR_LINK]                          = "TR_LINK",
+    [TR_EVDATA]                        = "TR_EVDATA",
+    [TR_NOOP]                          = "TR_NOOP",
+    [CR_ENABLE_SLOT]                   = "CR_ENABLE_SLOT",
+    [CR_DISABLE_SLOT]                  = "CR_DISABLE_SLOT",
+    [CR_ADDRESS_DEVICE]                = "CR_ADDRESS_DEVICE",
+    [CR_CONFIGURE_ENDPOINT]            = "CR_CONFIGURE_ENDPOINT",
+    [CR_EVALUATE_CONTEXT]              = "CR_EVALUATE_CONTEXT",
+    [CR_RESET_ENDPOINT]                = "CR_RESET_ENDPOINT",
+    [CR_STOP_ENDPOINT]                 = "CR_STOP_ENDPOINT",
+    [CR_SET_TR_DEQUEUE]                = "CR_SET_TR_DEQUEUE",
+    [CR_RESET_DEVICE]                  = "CR_RESET_DEVICE",
+    [CR_FORCE_EVENT]                   = "CR_FORCE_EVENT",
+    [CR_NEGOTIATE_BW]                  = "CR_NEGOTIATE_BW",
+    [CR_SET_LATENCY_TOLERANCE]         = "CR_SET_LATENCY_TOLERANCE",
+    [CR_GET_PORT_BANDWIDTH]            = "CR_GET_PORT_BANDWIDTH",
+    [CR_FORCE_HEADER]                  = "CR_FORCE_HEADER",
+    [CR_NOOP]                          = "CR_NOOP",
+    [ER_TRANSFER]                      = "ER_TRANSFER",
+    [ER_COMMAND_COMPLETE]              = "ER_COMMAND_COMPLETE",
+    [ER_PORT_STATUS_CHANGE]            = "ER_PORT_STATUS_CHANGE",
+    [ER_BANDWIDTH_REQUEST]             = "ER_BANDWIDTH_REQUEST",
+    [ER_DOORBELL]                      = "ER_DOORBELL",
+    [ER_HOST_CONTROLLER]               = "ER_HOST_CONTROLLER",
+    [ER_DEVICE_NOTIFICATION]           = "ER_DEVICE_NOTIFICATION",
+    [ER_MFINDEX_WRAP]                  = "ER_MFINDEX_WRAP",
+    [CR_VENDOR_VIA_CHALLENGE_RESPONSE] = "CR_VENDOR_VIA_CHALLENGE_RESPONSE",
+    [CR_VENDOR_NEC_FIRMWARE_REVISION]  = "CR_VENDOR_NEC_FIRMWARE_REVISION",
+    [CR_VENDOR_NEC_CHALLENGE_RESPONSE] = "CR_VENDOR_NEC_CHALLENGE_RESPONSE",
+};
+
+static const char *lookup_name(uint32_t index, const char **list, uint32_t llen)
+{
+    if (index >= llen || list[index] == NULL) {
+        return "???";
+    }
+    return list[index];
+}
+
+static const char *trb_name(XHCITRB *trb)
+{
+    return lookup_name(TRB_TYPE(*trb), TRBType_names,
+                       ARRAY_SIZE(TRBType_names));
+}
+#endif
+
 static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
                          unsigned int epid);
 
@@ -487,8 +541,9 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event)
     }
     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);
+    DPRINTF("xhci_write_event(): [%d] %016"PRIx64" %08x %08x %s\n",
+            xhci->er_ep_idx, ev_trb.parameter, ev_trb.status, ev_trb.control,
+            trb_name(&ev_trb));
 
     addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx;
     cpu_physical_memory_write(addr, (uint8_t *) &ev_trb, TRB_SIZE);
@@ -649,8 +704,9 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb,
         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);
+                "%016" PRIx64 " %08x %08x %s\n",
+                ring->dequeue, trb->parameter, trb->status, trb->control,
+                trb_name(trb));
 
         if ((trb->control & TRB_C) != ring->ccs) {
             return 0;
commit 606352b735eb98ce0b1f3786e0b4b313bd2e1a35
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jan 13 17:06:18 2012 +0100

    xhci: signal low- and fullspeed support
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c
index b274b80..27bdc2b 100644
--- a/hw/usb-xhci.c
+++ b/hw/usb-xhci.c
@@ -2672,7 +2672,10 @@ static void usb_xhci_init(XHCIState *xhci, DeviceState *dev)
     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);
+                          &xhci_port_ops,
+                          USB_SPEED_MASK_LOW  |
+                          USB_SPEED_MASK_FULL |
+                          USB_SPEED_MASK_HIGH);
     }
     for (i = 0; i < MAXSLOTS; i++) {
         xhci->slots[i].enabled = 0;
commit 37f32f0fdd3ed589266d159abb69f3a1bae20ec5
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jan 20 13:29:53 2012 +0100

    usb: add USBBusOps->wakeup_endpoint
    
    Add usb bus op which is called whenever a usb endpoint becomes ready,
    so the host adapter emulation can react on that event.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb.c b/hw/usb.c
index 0572547..e5b8f33 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -73,10 +73,14 @@ void usb_device_reset(USBDevice *dev)
 void usb_wakeup(USBEndpoint *ep)
 {
     USBDevice *dev = ep->dev;
+    USBBus *bus = usb_bus_from_device(dev);
 
     if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
         dev->port->ops->wakeup(dev->port);
     }
+    if (bus->ops->wakeup_endpoint) {
+        bus->ops->wakeup_endpoint(bus, ep);
+    }
 }
 
 /**********************/
diff --git a/hw/usb.h b/hw/usb.h
index b2caa77..4470ea8 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -425,6 +425,7 @@ struct USBBus {
 struct USBBusOps {
     int (*register_companion)(USBBus *bus, USBPort *ports[],
                               uint32_t portcount, uint32_t firstport);
+    void (*wakeup_endpoint)(USBBus *bus, USBEndpoint *ep);
 };
 
 void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
commit 7567b51fbe92e1300a672eaddd413c4a7e807d90
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jan 17 13:25:46 2012 +0100

    usb: pass USBEndpoint to usb_wakeup
    
    Devices must specify which endpoint has data to transfer now.
    The plan is to use the usb_wakeup() not only for remove wakeup support,
    but for "data ready" signaling in general, so we can move away from
    constant polling to event driven usb device emulation.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index 8c0c717..fda2d92 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -267,6 +267,7 @@ typedef struct CCIDBus {
  */
 typedef struct USBCCIDState {
     USBDevice dev;
+    USBEndpoint *intr;
     CCIDBus bus;
     CCIDCardState *card;
     BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */
@@ -839,7 +840,7 @@ static void ccid_on_slot_change(USBCCIDState *s, bool full)
         s->bmSlotICCState |= SLOT_0_CHANGED_MASK;
     }
     s->notify_slot_change = true;
-    usb_wakeup(&s->dev);
+    usb_wakeup(s->intr);
 }
 
 static void ccid_write_data_block_error(
@@ -1190,6 +1191,7 @@ static int ccid_initfn(USBDevice *dev)
 
     usb_desc_init(dev);
     qbus_create_inplace(&s->bus.qbus, &ccid_bus_info, &dev->qdev, NULL);
+    s->intr = usb_ep_get(dev, USB_TOKEN_IN, CCID_INT_IN_EP);
     s->bus.qbus.allow_hotplug = 1;
     s->card = NULL;
     s->migration_state = MIGRATION_NONE;
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 4d00c28..53353d3 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -44,6 +44,7 @@
 
 typedef struct USBHIDState {
     USBDevice dev;
+    USBEndpoint *intr;
     HIDState hid;
 } USBHIDState;
 
@@ -360,7 +361,7 @@ static void usb_hid_changed(HIDState *hs)
 {
     USBHIDState *us = container_of(hs, USBHIDState, hid);
 
-    usb_wakeup(&us->dev);
+    usb_wakeup(us->intr);
 }
 
 static void usb_hid_handle_reset(USBDevice *dev)
@@ -501,6 +502,7 @@ static int usb_hid_initfn(USBDevice *dev, int kind)
     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 
     usb_desc_init(dev);
+    us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
     hid_init(&us->hid, kind, usb_hid_changed);
     return 0;
 }
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 940e211..6d1ce06 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -37,6 +37,7 @@ typedef struct USBHubPort {
 
 typedef struct USBHubState {
     USBDevice dev;
+    USBEndpoint *intr;
     USBHubPort ports[NUM_PORTS];
 } USBHubState;
 
@@ -163,7 +164,7 @@ static void usb_hub_attach(USBPort *port1)
     } else {
         port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
     }
-    usb_wakeup(&s->dev);
+    usb_wakeup(s->intr);
 }
 
 static void usb_hub_detach(USBPort *port1)
@@ -171,7 +172,7 @@ static void usb_hub_detach(USBPort *port1)
     USBHubState *s = port1->opaque;
     USBHubPort *port = &s->ports[port1->index];
 
-    usb_wakeup(&s->dev);
+    usb_wakeup(s->intr);
 
     /* Let upstream know the device on this port is gone */
     s->dev.port->ops->child_detach(s->dev.port, port1->dev);
@@ -199,7 +200,7 @@ static void usb_hub_wakeup(USBPort *port1)
 
     if (port->wPortStatus & PORT_STAT_SUSPEND) {
         port->wPortChange |= PORT_STAT_C_SUSPEND;
-        usb_wakeup(&s->dev);
+        usb_wakeup(s->intr);
     }
 }
 
@@ -481,6 +482,7 @@ static int usb_hub_initfn(USBDevice *dev)
     int i;
 
     usb_desc_init(dev);
+    s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
     for (i = 0; i < NUM_PORTS; i++) {
         port = &s->ports[i];
         usb_register_port(usb_bus_from_device(dev),
diff --git a/hw/usb.c b/hw/usb.c
index 712bdd4..0572547 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -70,8 +70,10 @@ void usb_device_reset(USBDevice *dev)
     usb_device_handle_reset(dev);
 }
 
-void usb_wakeup(USBDevice *dev)
+void usb_wakeup(USBEndpoint *ep)
 {
+    USBDevice *dev = ep->dev;
+
     if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
         dev->port->ops->wakeup(dev->port);
     }
diff --git a/hw/usb.h b/hw/usb.h
index 6545b69..b2caa77 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -368,7 +368,7 @@ void usb_attach(USBPort *port);
 void usb_detach(USBPort *port);
 void usb_port_reset(USBPort *port);
 void usb_device_reset(USBDevice *dev);
-void usb_wakeup(USBDevice *dev);
+void usb_wakeup(USBEndpoint *ep);
 void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
 int set_usb_string(uint8_t *buf, const char *str);
 
commit db4be873d312576c6971da15a38e056017a406b8
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Jan 12 14:26:13 2012 +0100

    usb: maintain async packet list per endpoint
    
    Maintain a list of async packets per endpoint.  With the current code
    the list will never receive more than a single item.  I think you can
    guess what the future plan is though ;)
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb.c b/hw/usb.c
index 240f24b..712bdd4 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -279,6 +279,28 @@ USBDevice *usb_find_device(USBPort *port, uint8_t addr)
     return usb_device_find_device(dev, addr);
 }
 
+static int usb_process_one(USBPacket *p)
+{
+    USBDevice *dev = p->ep->dev;
+
+    if (p->ep->nr == 0) {
+        /* control pipe */
+        switch (p->pid) {
+        case USB_TOKEN_SETUP:
+            return do_token_setup(dev, p);
+        case USB_TOKEN_IN:
+            return do_token_in(dev, p);
+        case USB_TOKEN_OUT:
+            return do_token_out(dev, p);
+        default:
+            return USB_RET_STALL;
+        }
+    } else {
+        /* data pipe */
+        return usb_device_handle_data(dev, p);
+    }
+}
+
 /* Hand over a packet to a device for processing.  Return value
    USB_RET_ASYNC indicates the processing isn't finished yet, the
    driver will call usb_packet_complete() when done processing it. */
@@ -292,30 +314,21 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
     assert(dev == p->ep->dev);
     assert(dev->state == USB_STATE_DEFAULT);
     assert(p->state == USB_PACKET_SETUP);
+    assert(p->ep != NULL);
 
-    if (p->ep->nr == 0) {
-        /* control pipe */
-        switch (p->pid) {
-        case USB_TOKEN_SETUP:
-            ret = do_token_setup(dev, p);
-            break;
-        case USB_TOKEN_IN:
-            ret = do_token_in(dev, p);
-            break;
-        case USB_TOKEN_OUT:
-            ret = do_token_out(dev, p);
-            break;
-        default:
-            ret = USB_RET_STALL;
-            break;
+    if (QTAILQ_EMPTY(&p->ep->queue)) {
+        ret = usb_process_one(p);
+        if (ret == USB_RET_ASYNC) {
+            usb_packet_set_state(p, USB_PACKET_ASYNC);
+            QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
+        } else {
+            p->result = ret;
+            usb_packet_set_state(p, USB_PACKET_COMPLETE);
         }
     } else {
-        /* data pipe */
-        ret = usb_device_handle_data(dev, p);
-    }
-
-    if (ret == USB_RET_ASYNC) {
-        p->state = USB_PACKET_ASYNC;
+        ret = USB_RET_ASYNC;
+        usb_packet_set_state(p, USB_PACKET_QUEUED);
+        QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
     }
     return ret;
 }
@@ -325,9 +338,28 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
    handle_packet. */
 void usb_packet_complete(USBDevice *dev, USBPacket *p)
 {
+    USBEndpoint *ep = p->ep;
+    int ret;
+
     assert(p->state == USB_PACKET_ASYNC);
-    p->state = USB_PACKET_COMPLETE;
+    assert(QTAILQ_FIRST(&ep->queue) == p);
+    usb_packet_set_state(p, USB_PACKET_COMPLETE);
+    QTAILQ_REMOVE(&ep->queue, p, queue);
     dev->port->ops->complete(dev->port, p);
+
+    while (!QTAILQ_EMPTY(&ep->queue)) {
+        p = QTAILQ_FIRST(&ep->queue);
+        assert(p->state == USB_PACKET_QUEUED);
+        ret = usb_process_one(p);
+        if (ret == USB_RET_ASYNC) {
+            usb_packet_set_state(p, USB_PACKET_ASYNC);
+            break;
+        }
+        p->result = ret;
+        usb_packet_set_state(p, USB_PACKET_COMPLETE);
+        QTAILQ_REMOVE(&ep->queue, p, queue);
+        dev->port->ops->complete(dev->port, p);
+    }
 }
 
 /* Cancel an active packet.  The packed must have been deferred by
@@ -335,9 +367,13 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
    completed.  */
 void usb_cancel_packet(USBPacket * p)
 {
-    assert(p->state == USB_PACKET_ASYNC);
-    p->state = USB_PACKET_CANCELED;
-    usb_device_cancel_packet(p->ep->dev, p);
+    bool callback = (p->state == USB_PACKET_ASYNC);
+    assert(usb_packet_is_inflight(p));
+    usb_packet_set_state(p, USB_PACKET_CANCELED);
+    QTAILQ_REMOVE(&p->ep->queue, p, queue);
+    if (callback) {
+        usb_device_cancel_packet(p->ep->dev, p);
+    }
 }
 
 
@@ -346,14 +382,50 @@ void usb_packet_init(USBPacket *p)
     qemu_iovec_init(&p->iov, 1);
 }
 
+void usb_packet_set_state(USBPacket *p, USBPacketState state)
+{
+#ifdef DEBUG
+    static const char *name[] = {
+        [USB_PACKET_UNDEFINED] = "undef",
+        [USB_PACKET_SETUP]     = "setup",
+        [USB_PACKET_QUEUED]    = "queued",
+        [USB_PACKET_ASYNC]     = "async",
+        [USB_PACKET_COMPLETE]  = "complete",
+        [USB_PACKET_CANCELED]  = "canceled",
+    };
+    static const char *rets[] = {
+        [-USB_RET_NODEV]  = "NODEV",
+        [-USB_RET_NAK]    = "NAK",
+        [-USB_RET_STALL]  = "STALL",
+        [-USB_RET_BABBLE] = "BABBLE",
+        [-USB_RET_ASYNC]  = "ASYNC",
+    };
+    char add[16] = "";
+
+    if (state == USB_PACKET_COMPLETE) {
+        if (p->result < 0) {
+            snprintf(add, sizeof(add), " - %s", rets[-p->result]);
+        } else {
+            snprintf(add, sizeof(add), " - %d", p->result);
+        }
+    }
+    fprintf(stderr, "bus %s, port %s, dev %d, ep %d: packet %p: %s -> %s%s\n",
+            p->ep->dev->qdev.parent_bus->name,
+            p->ep->dev->port->path,
+            p->ep->dev->addr, p->ep->nr,
+            p, name[p->state], name[state], add);
+#endif
+    p->state = state;
+}
+
 void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep)
 {
     assert(!usb_packet_is_inflight(p));
-    p->state = USB_PACKET_SETUP;
     p->pid = pid;
     p->ep = ep;
     p->result = 0;
     qemu_iovec_reset(&p->iov);
+    usb_packet_set_state(p, USB_PACKET_SETUP);
 }
 
 void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len)
@@ -404,6 +476,7 @@ void usb_ep_init(USBDevice *dev)
     dev->ep_ctl.type = USB_ENDPOINT_XFER_CONTROL;
     dev->ep_ctl.ifnum = 0;
     dev->ep_ctl.dev = dev;
+    QTAILQ_INIT(&dev->ep_ctl.queue);
     for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
         dev->ep_in[ep].nr = ep + 1;
         dev->ep_out[ep].nr = ep + 1;
@@ -415,6 +488,8 @@ void usb_ep_init(USBDevice *dev)
         dev->ep_out[ep].ifnum = 0;
         dev->ep_in[ep].dev = dev;
         dev->ep_out[ep].dev = dev;
+        QTAILQ_INIT(&dev->ep_in[ep].queue);
+        QTAILQ_INIT(&dev->ep_out[ep].queue);
     }
 }
 
diff --git a/hw/usb.h b/hw/usb.h
index a80fe8f..6545b69 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -177,6 +177,7 @@ struct USBEndpoint {
     uint8_t ifnum;
     int max_packet_size;
     USBDevice *dev;
+    QTAILQ_HEAD(, USBPacket) queue;
 };
 
 /* definition of a USB device */
@@ -309,15 +310,16 @@ struct USBPort {
 
 typedef void USBCallback(USBPacket * packet, void *opaque);
 
-/* Structure used to hold information about an active USB packet.  */
 typedef enum USBPacketState {
     USB_PACKET_UNDEFINED = 0,
     USB_PACKET_SETUP,
+    USB_PACKET_QUEUED,
     USB_PACKET_ASYNC,
     USB_PACKET_COMPLETE,
     USB_PACKET_CANCELED,
 } USBPacketState;
 
+/* Structure used to hold information about an active USB packet.  */
 struct USBPacket {
     /* Data fields for use by the driver.  */
     int pid;
@@ -326,9 +328,11 @@ struct USBPacket {
     int result; /* transfer length or USB_RET_* status code */
     /* Internal use by the USB layer.  */
     USBPacketState state;
+    QTAILQ_ENTRY(USBPacket) queue;
 };
 
 void usb_packet_init(USBPacket *p);
+void usb_packet_set_state(USBPacket *p, USBPacketState state);
 void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep);
 void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len);
 int usb_packet_map(USBPacket *p, QEMUSGList *sgl);
@@ -339,7 +343,8 @@ void usb_packet_cleanup(USBPacket *p);
 
 static inline bool usb_packet_is_inflight(USBPacket *p)
 {
-    return p->state == USB_PACKET_ASYNC;
+    return (p->state == USB_PACKET_QUEUED ||
+            p->state == USB_PACKET_ASYNC);
 }
 
 USBDevice *usb_find_device(USBPort *port, uint8_t addr);
commit 3a0c6c4ad6f97931f1d9a729322cb1612218ed96
Author: Paul Brook <paul at codesourcery.com>
Date:   Thu Feb 9 19:04:27 2012 +0000

    linux-user: brk() debugging
    
    Fix format type mismatches in do_brk debug printfs.
    
    Signed-off-by: Paul Brook <paul at codesourcery.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index e868ec6..8a11213 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -756,14 +756,15 @@ abi_long do_brk(abi_ulong new_brk)
     abi_long mapped_addr;
     int	new_alloc_size;
 
-    DEBUGF_BRK("do_brk(%#010x) -> ", new_brk);
+    DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
 
     if (!new_brk) {
-        DEBUGF_BRK("%#010x (!new_brk)\n", target_brk);
+        DEBUGF_BRK(TARGET_ABI_FMT_lx " (!new_brk)\n", target_brk);
         return target_brk;
     }
     if (new_brk < target_original_brk) {
-        DEBUGF_BRK("%#010x (new_brk < target_original_brk)\n", target_brk);
+        DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk < target_original_brk)\n",
+                   target_brk);
         return target_brk;
     }
 
@@ -776,7 +777,7 @@ abi_long do_brk(abi_ulong new_brk)
             memset(g2h(target_brk), 0, new_brk - target_brk);
         }
 	target_brk = new_brk;
-        DEBUGF_BRK("%#010x (new_brk <= brk_page)\n", target_brk);
+        DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
     	return target_brk;
     }
 
@@ -803,7 +804,8 @@ abi_long do_brk(abi_ulong new_brk)
 
         target_brk = new_brk;
         brk_page = HOST_PAGE_ALIGN(target_brk);
-        DEBUGF_BRK("%#010x (mapped_addr == brk_page)\n", target_brk);
+        DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr == brk_page)\n",
+            target_brk);
         return target_brk;
     } else if (mapped_addr != -1) {
         /* Mapped but at wrong address, meaning there wasn't actually
@@ -811,10 +813,10 @@ abi_long do_brk(abi_ulong new_brk)
          */
         target_munmap(mapped_addr, new_alloc_size);
         mapped_addr = -1;
-        DEBUGF_BRK("%#010x (mapped_addr != -1)\n", target_brk);
+        DEBUGF_BRK(TARGET_ABI_FMT_lx " (mapped_addr != -1)\n", target_brk);
     }
     else {
-        DEBUGF_BRK("%#010x (otherwise)\n", target_brk);
+        DEBUGF_BRK(TARGET_ABI_FMT_lx " (otherwise)\n", target_brk);
     }
 
 #if defined(TARGET_ALPHA)
commit 6f79e06b35b26a1beda6f6dc4dd02588887597e9
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Thu Feb 9 11:29:42 2012 -0200

    virtio: Remove unneeded g_free() check in virtio_cleanup()
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/virtio.c b/hw/virtio.c
index 74cc038..064aecf 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -845,8 +845,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
 void virtio_cleanup(VirtIODevice *vdev)
 {
     qemu_del_vm_change_state_handler(vdev->vmstate);
-    if (vdev->config)
-        g_free(vdev->config);
+    g_free(vdev->config);
     g_free(vdev->vq);
     g_free(vdev);
 }
commit da8d605733c9b368230a716cc71c7915902387db
Author: Benjamin MARSILI <mlspirat42 at gmail.com>
Date:   Mon Jan 23 03:42:38 2012 +0900

    net: remove extra spaces in help messages
    
    Signed-off-by: Benjamin MARSILI <mlspirat42 at gmail.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/net/socket.c b/net/socket.c
index d4c2002..0bcf229 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -664,8 +664,8 @@ int net_init_socket(QemuOpts *opts,
             qemu_opt_get(opts, "connect") ||
             qemu_opt_get(opts, "listen") ||
             qemu_opt_get(opts, "mcast")) {
-            error_report("fd=, connect=, listen=\
-                         and mcast= is invalid with udp=");
+            error_report("fd=, connect=, listen="
+                         " and mcast= is invalid with udp=");
             return -1;
         }
 
@@ -680,8 +680,8 @@ int net_init_socket(QemuOpts *opts,
             return -1;
         }
     } else {
-        error_report("-socket requires fd=, listen=, \
-                     connect=, mcast= or udp=");
+        error_report("-socket requires fd=, listen=,"
+                     " connect=, mcast= or udp=");
         return -1;
     }
     return 0;
commit 31de83140d23ccc0e290bc0de609ba2b1aff674a
Author: Stefan Weil <sw at weilnetz.de>
Date:   Tue Feb 7 22:26:29 2012 +0100

    fmopl: Fix typo in function name
    
    Fix a typo in a local function name.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/fmopl.c b/hw/fmopl.c
index 734d2f4..f0a0234 100644
--- a/hw/fmopl.c
+++ b/hw/fmopl.c
@@ -733,7 +733,7 @@ INLINE void CSMKeyControll(OPL_CH *CH)
 }
 
 /* ---------- opl initialize ---------- */
-static void OPL_initalize(FM_OPL *OPL)
+static void OPL_initialize(FM_OPL *OPL)
 {
 	int fn;
 
@@ -1239,7 +1239,7 @@ FM_OPL *OPLCreate(int type, int clock, int rate)
 	OPL->rate  = rate;
 	OPL->max_ch = max_ch;
 	/* init grobal tables */
-	OPL_initalize(OPL);
+	OPL_initialize(OPL);
 	/* reset chip */
 	OPLResetChip(OPL);
 #ifdef OPL_OUTPUT_LOG
commit 1b785a975830993fff988028d90f2b55b2ab41f0
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Feb 7 20:57:27 2012 +0000

    vl.c: Fix typo in variable name
    
    Fix a typo in a local variable name.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/vl.c b/vl.c
index 63dd725..c4b3aab 100644
--- a/vl.c
+++ b/vl.c
@@ -2030,7 +2030,7 @@ static int configure_accelerator(void)
     const char *p = NULL;
     char buf[10];
     int i, ret;
-    bool accel_initalised = 0;
+    bool accel_initialised = 0;
     bool init_failed = 0;
 
     QemuOptsList *list = qemu_find_opts("machine");
@@ -2043,7 +2043,7 @@ static int configure_accelerator(void)
         p = "tcg";
     }
 
-    while (!accel_initalised && *p != '\0') {
+    while (!accel_initialised && *p != '\0') {
         if (*p == ':') {
             p++;
         }
@@ -2064,7 +2064,7 @@ static int configure_accelerator(void)
                     }
                     *(accel_list[i].allowed) = 0;
                 } else {
-                    accel_initalised = 1;
+                    accel_initialised = 1;
                 }
                 break;
             }
@@ -2074,7 +2074,7 @@ static int configure_accelerator(void)
         }
     }
 
-    if (!accel_initalised) {
+    if (!accel_initialised) {
         fprintf(stderr, "No accelerator found!\n");
         exit(1);
     }
@@ -2083,7 +2083,7 @@ static int configure_accelerator(void)
         fprintf(stderr, "Back to %s accelerator.\n", accel_list[i].name);
     }
 
-    return !accel_initalised;
+    return !accel_initialised;
 }
 
 void qemu_add_exit_notifier(Notifier *notify)
commit cb67be85a612e8b9ab25edb68976c0fa203d12ba
Author: Hervé Poussineau <hpoussin at reactos.org>
Date:   Mon Feb 6 22:19:42 2012 +0100

    ide: fix compilation errors when DEBUG_IDE is set
    
    Signed-off-by: Hervé Poussineau <hpoussin at reactos.org>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 246dd57..88c0942 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -336,7 +336,7 @@ static uint64_t bmdma_addr_read(void *opaque, target_phys_addr_t addr,
 
     data = (bm->addr >> (addr * 8)) & mask;
 #ifdef DEBUG_IDE
-    printf("%s: 0x%08x\n", __func__, (unsigned)*data);
+    printf("%s: 0x%08x\n", __func__, (unsigned)data);
 #endif
     return data;
 }
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index bf4465b..76cf209 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -53,7 +53,7 @@ static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr, unsigned size)
         break;
     }
 #ifdef DEBUG_IDE
-    printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val);
+    printf("bmdma: readb 0x%02x : 0x%02x\n", (uint8_t)addr, val);
 #endif
     return val;
 }
@@ -68,7 +68,7 @@ static void bmdma_write(void *opaque, target_phys_addr_t addr,
     }
 
 #ifdef DEBUG_IDE
-    printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
+    printf("bmdma: writeb 0x%02x : 0x%02x\n", (uint8_t)addr, (uint8_t)val);
 #endif
     switch(addr & 3) {
     case 0:
commit e965fc380703110e967febf8d5b2ecd7db53b5d2
Author: 陳韋任 <chenwj at iis.sinica.edu.tw>
Date:   Mon Feb 6 14:02:55 2012 +0800

    cpu-exec.c: Correct comment about this file and indentation cleanup
    
    Each target uses the #define macro (in target-xxx/cpu.h) to rename
    cpu_exec (cpu-exec.c) to cpu_xxx_exec, then defines its own cpu_loop
    which calls cpu_xxx_exec. So basically, cpu-exec.c is not only the i386
    emulator main execution loop. This patch corrects the comment of this
    file and does indentation cleanup.
    
    Signed-off-by: Chen Wei-Ren (陳韋任) <chenwj at iis.sinica.edu.tw>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/cpu-exec.c b/cpu-exec.c
index a9fa608..2c2d24e 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -1,5 +1,5 @@
 /*
- *  i386 emulator main execution loop
+ *  emulator main execution loop
  *
  *  Copyright (c) 2003-2005 Fabrice Bellard
  *
@@ -304,7 +304,7 @@ int cpu_exec(CPUState *env)
                             env->hflags2 |= HF2_NMI_MASK;
                             do_interrupt_x86_hardirq(env, EXCP02_NMI, 1);
                             next_tb = 0;
-			} else if (interrupt_request & CPU_INTERRUPT_MCE) {
+                        } else if (interrupt_request & CPU_INTERRUPT_MCE) {
                             env->interrupt_request &= ~CPU_INTERRUPT_MCE;
                             do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0);
                             next_tb = 0;
@@ -390,7 +390,7 @@ int cpu_exec(CPUState *env)
                                 next_tb = 0;
                             }
                         }
-		    }
+                    }
 #elif defined(TARGET_ARM)
                     if (interrupt_request & CPU_INTERRUPT_FIQ
                         && !(env->uncached_cpsr & CPSR_F)) {
@@ -429,7 +429,7 @@ int cpu_exec(CPUState *env)
                     {
                         int idx = -1;
                         /* ??? This hard-codes the OSF/1 interrupt levels.  */
-		        switch (env->pal_mode ? 7 : env->ps & PS_INT_MASK) {
+                        switch (env->pal_mode ? 7 : env->ps & PS_INT_MASK) {
                         case 0 ... 3:
                             if (interrupt_request & CPU_INTERRUPT_HARD) {
                                 idx = EXCP_DEV_INTERRUPT;
@@ -562,7 +562,7 @@ int cpu_exec(CPUState *env)
                 barrier();
                 if (likely(!env->exit_request)) {
                     tc_ptr = tb->tc_ptr;
-                /* execute the generated code */
+                    /* execute the generated code */
                     next_tb = tcg_qemu_tb_exec(env, tc_ptr);
                     if ((next_tb & 3) == 2) {
                         /* Instruction counter expired.  */
commit e3c52bf2e59a1caa7a8f4d1eb069cc1406075d10
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Jan 13 20:29:49 2012 +0000

    CODING_STYLE: Clarify style for enum and function type names
    
    Clarify that enum type names and function type names should follow
    the CamelCase style used for structured type names.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/CODING_STYLE b/CODING_STYLE
index 6e61c49..7c82d4d 100644
--- a/CODING_STYLE
+++ b/CODING_STYLE
@@ -44,7 +44,8 @@ Rationale:
 3. Naming
 
 Variables are lower_case_with_underscores; easy to type and read.  Structured
-type names are in CamelCase; harder to type but standing out.  Scalar type
+type names are in CamelCase; harder to type but standing out.  Enum type
+names and function type names should also be in CamelCase.  Scalar type
 names are lower_case_with_underscores_ending_with_a_t, like the POSIX
 uint64_t and family.  Note that this last convention contradicts POSIX
 and is therefore likely to be changed.
commit a6f79cc9a5efc34c5b751b2e866a4977259f3f63
Author: Ulrich Hecht <uli at suse.de>
Date:   Tue Jan 31 12:43:16 2012 +0100

    linux-user: fail execve() if env/args too big
    
    If the host's page size is equal to or smaller than the target's, native
    execve() will fail appropriately with E2BIG if called with too big an
    environment for the target to handle. It may falsely succeed, however, if
    the host's page size is bigger, and feed the executed target process an
    environment that is too big for it to handle, at which point QEMU barfs and
    exits, confusing procmail's autoconf script and causing the build to fail.
    
    This patch makes sure that execve() will return E2BIG if the environment is
    too large for the target.
    
    Signed-off-by: Ulrich Hecht <uli at suse.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index ee8899e..e868ec6 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -4949,6 +4949,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             abi_ulong guest_envp;
             abi_ulong addr;
             char **q;
+            int total_size = 0;
 
             argc = 0;
             guest_argp = arg2;
@@ -4980,6 +4981,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                     break;
                 if (!(*q = lock_user_string(addr)))
                     goto execve_efault;
+                total_size += strlen(*q) + 1;
             }
             *q = NULL;
 
@@ -4991,9 +4993,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                     break;
                 if (!(*q = lock_user_string(addr)))
                     goto execve_efault;
+                total_size += strlen(*q) + 1;
             }
             *q = NULL;
 
+            /* This case will not be caught by the host's execve() if its
+               page size is bigger than the target's. */
+            if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
+                ret = -TARGET_E2BIG;
+                goto execve_end;
+            }
             if (!(p = lock_user_string(arg1)))
                 goto execve_efault;
             ret = get_errno(execve(p, argp, envp));
commit 079d0b7f1eedcc634c371fe05b617fdc55c8b762
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Jan 12 13:23:01 2012 +0100

    usb: Set USBEndpoint in usb_packet_setup().
    
    With the separation of the device lookup (via usb_find_device) and
    packet processing we can lookup device and endpoint before setting up
    the usb packet.  So we can initialize USBPacket->ep early and keep it
    valid for the whole lifecycle of the USBPacket.  Also the devaddr and
    devep fields are not needed any more.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-audio.c b/hw/usb-audio.c
index a4ea0b0..c60aaff 100644
--- a/hw/usb-audio.c
+++ b/hw/usb-audio.c
@@ -607,7 +607,7 @@ static int usb_audio_handle_data(USBDevice *dev, USBPacket *p)
 
     switch (p->pid) {
     case USB_TOKEN_OUT:
-        switch (p->devep) {
+        switch (p->ep->nr) {
         case 1:
             ret = usb_audio_handle_dataout(s, p);
             break;
@@ -624,7 +624,7 @@ fail:
     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);
+                        p->pid, p->ep->nr, p->iov.size);
     }
     return ret;
 }
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index 58b247e..ea6a5a0 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -423,7 +423,7 @@ static int usb_bt_handle_data(USBDevice *dev, USBPacket *p)
 
     switch (p->pid) {
     case USB_TOKEN_IN:
-        switch (p->devep & 0xf) {
+        switch (p->ep->nr) {
         case USB_EVT_EP:
             ret = usb_bt_fifo_dequeue(&s->evt, p);
             break;
@@ -442,7 +442,7 @@ static int usb_bt_handle_data(USBDevice *dev, USBPacket *p)
         break;
 
     case USB_TOKEN_OUT:
-        switch (p->devep & 0xf) {
+        switch (p->ep->nr) {
         case USB_ACL_EP:
             usb_bt_fifo_out_enqueue(s, &s->outacl, s->hci->acl_send,
                             usb_bt_hci_acl_complete, p);
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index b3bcfeb..8c0c717 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -995,7 +995,7 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p)
         break;
 
     case USB_TOKEN_IN:
-        switch (p->devep & 0xf) {
+        switch (p->ep->nr) {
         case CCID_BULK_IN_EP:
             if (!p->iov.size) {
                 ret = USB_RET_NAK;
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index f0213ad..6c01ca9 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -1357,6 +1357,7 @@ err:
 static int ehci_execute(EHCIQueue *q)
 {
     USBDevice *dev;
+    USBEndpoint *ep;
     int ret;
     int endp;
     int devadr;
@@ -1387,13 +1388,13 @@ static int ehci_execute(EHCIQueue *q)
     endp = get_field(q->qh.epchar, QH_EPCHAR_EP);
     devadr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR);
 
-    ret = USB_RET_NODEV;
+    /* TODO: associating device with ehci port */
+    dev = ehci_find_device(q->ehci, devadr);
+    ep = usb_ep_get(dev, q->pid, endp);
 
-    usb_packet_setup(&q->packet, q->pid, devadr, endp);
+    usb_packet_setup(&q->packet, q->pid, ep);
     usb_packet_map(&q->packet, &q->sgl);
 
-    // TO-DO: associating device with ehci port
-    dev = ehci_find_device(q->ehci, q->packet.devaddr);
     ret = usb_handle_packet(dev, &q->packet);
     DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd "
             "(total %d) endp %x ret %d\n",
@@ -1415,6 +1416,7 @@ static int ehci_process_itd(EHCIState *ehci,
                             EHCIitd *itd)
 {
     USBDevice *dev;
+    USBEndpoint *ep;
     int ret;
     uint32_t i, len, pid, dir, devaddr, endp;
     uint32_t pg, off, ptr1, ptr2, max, mult;
@@ -1454,10 +1456,11 @@ static int ehci_process_itd(EHCIState *ehci,
 
             pid = dir ? USB_TOKEN_IN : USB_TOKEN_OUT;
 
-            usb_packet_setup(&ehci->ipacket, pid, devaddr, endp);
+            dev = ehci_find_device(ehci, devaddr);
+            ep = usb_ep_get(dev, pid, endp);
+            usb_packet_setup(&ehci->ipacket, pid, ep);
             usb_packet_map(&ehci->ipacket, &ehci->isgl);
 
-            dev = ehci_find_device(ehci, ehci->ipacket.devaddr);
             ret = usb_handle_packet(dev, &ehci->ipacket);
 
             usb_packet_unmap(&ehci->ipacket);
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index c648980..4d00c28 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -463,7 +463,7 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
 
     switch (p->pid) {
     case USB_TOKEN_IN:
-        if (p->devep == 1) {
+        if (p->ep->nr == 1) {
             int64_t curtime = qemu_get_clock_ns(vm_clock);
             if (!hid_has_events(hs) &&
                 (!hs->idle || hs->next_idle_clock - curtime > 0)) {
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 2256256..940e211 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -416,7 +416,7 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
 
     switch(p->pid) {
     case USB_TOKEN_IN:
-        if (p->devep == 1) {
+        if (p->ep->nr == 1) {
             USBHubPort *port;
             unsigned int status;
             uint8_t buf[4];
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index c34cad5..aac1181 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -341,7 +341,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
     uint32_t tag;
     int ret = 0;
     struct usb_msd_cbw cbw;
-    uint8_t devep = p->devep;
+    uint8_t devep = p->ep->nr;
 
     switch (p->pid) {
     case USB_TOKEN_OUT:
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index f4e52f1..820907a 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -606,6 +606,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
                 int epnum, int pid, int len, USBCallback cb, int dir)
 {
     USBDevice *dev;
+    USBEndpoint *uep;
     int ret;
     int idx = epnum && dir;
     int ttype;
@@ -623,13 +624,13 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
     ep->delayed_cb[dir] = cb;
 
     /* A wild guess on the FADDR semantics... */
-    usb_packet_setup(&ep->packey[dir].p, pid, ep->faddr[idx],
-                     ep->type[idx] & 0xf);
+    dev = usb_find_device(&s->port, ep->faddr[idx]);
+    uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf);
+    usb_packet_setup(&ep->packey[dir].p, pid, uep);
     usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
     ep->packey[dir].ep = ep;
     ep->packey[dir].dir = dir;
 
-    dev = usb_find_device(&s->port, ep->packey[dir].p.devaddr);
     ret = usb_handle_packet(dev, &ep->packey[dir].p);
 
     if (ret == USB_RET_ASYNC) {
diff --git a/hw/usb-net.c b/hw/usb-net.c
index f00e854..72c9185 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1210,7 +1210,7 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
 
     switch(p->pid) {
     case USB_TOKEN_IN:
-        switch (p->devep) {
+        switch (p->ep->nr) {
         case 1:
             ret = usb_net_handle_statusin(s, p);
             break;
@@ -1225,7 +1225,7 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
         break;
 
     case USB_TOKEN_OUT:
-        switch (p->devep) {
+        switch (p->ep->nr) {
         case 2:
             ret = usb_net_handle_dataout(s, p);
             break;
@@ -1243,7 +1243,7 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
     if (ret == USB_RET_STALL)
         fprintf(stderr, "usbnet: failed data transaction: "
                         "pid 0x%x ep 0x%x len 0x%zx\n",
-                        p->pid, p->devep, p->iov.size);
+                        p->pid, p->ep->nr, p->iov.size);
     return ret;
 }
 
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 8a8f3bc..ba7231f 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -657,6 +657,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
     int ret;
     int i;
     USBDevice *dev;
+    USBEndpoint *ep;
     struct ohci_iso_td iso_td;
     uint32_t addr;
     uint16_t starting_frame;
@@ -796,11 +797,10 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
     if (completion) {
         ret = ohci->usb_packet.result;
     } else {
-        usb_packet_setup(&ohci->usb_packet, pid,
-                         OHCI_BM(ed->flags, ED_FA),
-                         OHCI_BM(ed->flags, ED_EN));
+        dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
+        ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
+        usb_packet_setup(&ohci->usb_packet, pid, ep);
         usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
-        dev = ohci_find_device(ohci, ohci->usb_packet.devaddr);
         ret = usb_handle_packet(dev, &ohci->usb_packet);
         if (ret == USB_RET_ASYNC) {
             return 1;
@@ -889,6 +889,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
     int ret;
     int i;
     USBDevice *dev;
+    USBEndpoint *ep;
     struct ohci_td td;
     uint32_t addr;
     int flag_r;
@@ -992,11 +993,10 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
 #endif
             return 1;
         }
-        usb_packet_setup(&ohci->usb_packet, pid,
-                         OHCI_BM(ed->flags, ED_FA),
-                         OHCI_BM(ed->flags, ED_EN));
+        dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
+        ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
+        usb_packet_setup(&ohci->usb_packet, pid, ep);
         usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
-        dev = ohci_find_device(ohci, ohci->usb_packet.devaddr);
         ret = usb_handle_packet(dev, &ohci->usb_packet);
 #ifdef DEBUG_PACKET
         DPRINTF("ret=%d\n", ret);
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index cf83cf2..1cfb551 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -353,7 +353,7 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
 {
     USBSerialState *s = (USBSerialState *)dev;
     int i, ret = 0;
-    uint8_t devep = p->devep;
+    uint8_t devep = p->ep->nr;
     struct iovec *iov;
     uint8_t header[2];
     int first_len, len;
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index ef08145..ab64be6 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -761,6 +761,8 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
     int len = 0, max_len;
     uint8_t pid, isoc;
     uint32_t token;
+    USBDevice *dev;
+    USBEndpoint *ep;
 
     /* Is active ? */
     if (!(td->ctrl & TD_CTRL_ACTIVE))
@@ -805,23 +807,22 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
     max_len = ((td->token >> 21) + 1) & 0x7ff;
     pid = td->token & 0xff;
 
-    usb_packet_setup(&async->packet, pid, (td->token >> 8) & 0x7f,
-                     (td->token >> 15) & 0xf);
+    dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
+    ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf);
+    usb_packet_setup(&async->packet, pid, ep);
     qemu_sglist_add(&async->sgl, td->buffer, max_len);
     usb_packet_map(&async->packet, &async->sgl);
 
     switch(pid) {
     case USB_TOKEN_OUT:
     case USB_TOKEN_SETUP:
-        len = usb_handle_packet(uhci_find_device(s, async->packet.devaddr),
-                                &async->packet);
+        len = usb_handle_packet(dev, &async->packet);
         if (len >= 0)
             len = max_len;
         break;
 
     case USB_TOKEN_IN:
-        len = usb_handle_packet(uhci_find_device(s, async->packet.devaddr),
-                                &async->packet);
+        len = usb_handle_packet(dev, &async->packet);
         break;
 
     default:
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 46b8010..73ff241 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -306,7 +306,7 @@ static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
 
     switch (p->pid) {
     case USB_TOKEN_IN:
-        if (p->devep == 1) {
+        if (p->ep->nr == 1) {
             if (!(s->changed || s->idle))
                 return USB_RET_NAK;
             s->changed = 0;
diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c
index aa236c9..b274b80 100644
--- a/hw/usb-xhci.c
+++ b/hw/usb-xhci.c
@@ -1336,15 +1336,17 @@ static int xhci_hle_control(XHCIState *xhci, XHCITransfer *xfer,
 }
 #endif
 
-static int xhci_setup_packet(XHCITransfer *xfer, XHCIPort *port, int ep)
+static int xhci_setup_packet(XHCITransfer *xfer, XHCIPort *port, USBDevice *dev)
 {
-    usb_packet_setup(&xfer->packet,
-                     xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT,
-                     xfer->xhci->slots[xfer->slotid-1].devaddr,
-                     ep & 0x7f);
+    USBEndpoint *ep;
+    int dir;
+
+    dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT;
+    ep = usb_ep_get(dev, dir, xfer->epid >> 1);
+    usb_packet_setup(&xfer->packet, dir, ep);
     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);
+            xfer->packet.pid, dev->addr, ep->nr);
     return 0;
 }
 
@@ -1462,7 +1464,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
     xfer->in_xfer = bmRequestType & USB_DIR_IN;
     xfer->iso_xfer = false;
 
-    xhci_setup_packet(xfer, port, 0);
+    xhci_setup_packet(xfer, port, dev);
     if (!xfer->in_xfer) {
         xhci_xfer_data(xfer, xfer->data, wLength, 0, 1, 0);
     }
@@ -1484,12 +1486,8 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
     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;
@@ -1517,7 +1515,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
         return -1;
     }
 
-    xhci_setup_packet(xfer, port, ep);
+    xhci_setup_packet(xfer, port, dev);
 
     switch(epctx->type) {
     case ET_INTR_OUT:
@@ -1530,8 +1528,9 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
         FIXME();
         break;
     default:
-        fprintf(stderr, "xhci: unknown or unhandled EP type %d (ep %02x)\n",
-                epctx->type, ep);
+        fprintf(stderr, "xhci: unknown or unhandled EP "
+                "(type %d, in %d, ep %02x)\n",
+                epctx->type, xfer->in_xfer, xfer->epid);
         return -1;
     }
 
diff --git a/hw/usb.c b/hw/usb.c
index 8bd1222..240f24b 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -140,7 +140,7 @@ static int do_token_in(USBDevice *s, USBPacket *p)
     int request, value, index;
     int ret = 0;
 
-    assert(p->devep == 0);
+    assert(p->ep->nr == 0);
 
     request = (s->setup_buf[0] << 8) | s->setup_buf[1];
     value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
@@ -186,7 +186,7 @@ static int do_token_in(USBDevice *s, USBPacket *p)
 
 static int do_token_out(USBDevice *s, USBPacket *p)
 {
-    assert(p->devep == 0);
+    assert(p->ep->nr == 0);
 
     switch(s->setup_state) {
     case SETUP_STATE_ACK:
@@ -289,11 +289,11 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
     if (dev == NULL) {
         return USB_RET_NODEV;
     }
-    assert(dev->addr == p->devaddr);
+    assert(dev == p->ep->dev);
     assert(dev->state == USB_STATE_DEFAULT);
     assert(p->state == USB_PACKET_SETUP);
 
-    if (p->devep == 0) {
+    if (p->ep->nr == 0) {
         /* control pipe */
         switch (p->pid) {
         case USB_TOKEN_SETUP:
@@ -315,7 +315,6 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
     }
 
     if (ret == USB_RET_ASYNC) {
-        p->ep = usb_ep_get(dev, p->pid, p->devep);
         p->state = USB_PACKET_ASYNC;
     }
     return ret;
@@ -347,13 +346,12 @@ void usb_packet_init(USBPacket *p)
     qemu_iovec_init(&p->iov, 1);
 }
 
-void usb_packet_setup(USBPacket *p, int pid, uint8_t addr, uint8_t ep)
+void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep)
 {
     assert(!usb_packet_is_inflight(p));
     p->state = USB_PACKET_SETUP;
     p->pid = pid;
-    p->devaddr = addr;
-    p->devep = ep;
+    p->ep = ep;
     p->result = 0;
     qemu_iovec_reset(&p->iov);
 }
@@ -464,7 +462,12 @@ void usb_ep_dump(USBDevice *dev)
 
 struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep)
 {
-    struct USBEndpoint *eps = pid == USB_TOKEN_IN ? dev->ep_in : dev->ep_out;
+    struct USBEndpoint *eps;
+
+    if (dev == NULL) {
+        return NULL;
+    }
+    eps = (pid == USB_TOKEN_IN) ? dev->ep_in : dev->ep_out;
     if (ep == 0) {
         return &dev->ep_ctl;
     }
diff --git a/hw/usb.h b/hw/usb.h
index 1e629af..a80fe8f 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -321,8 +321,6 @@ typedef enum USBPacketState {
 struct USBPacket {
     /* Data fields for use by the driver.  */
     int pid;
-    uint8_t devaddr;
-    uint8_t devep;
     USBEndpoint *ep;
     QEMUIOVector iov;
     int result; /* transfer length or USB_RET_* status code */
@@ -331,7 +329,7 @@ struct USBPacket {
 };
 
 void usb_packet_init(USBPacket *p);
-void usb_packet_setup(USBPacket *p, int pid, uint8_t addr, uint8_t ep);
+void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep);
 void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len);
 int usb_packet_map(USBPacket *p, QEMUSGList *sgl);
 void usb_packet_unmap(USBPacket *p);
diff --git a/usb-bsd.c b/usb-bsd.c
index ca9a1bd..e4c01d3 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -214,7 +214,7 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
     int ret, fd, mode;
     int one = 1, shortpacket = 0, timeout = 50;
     sigset_t new_mask, old_mask;
-    uint8_t devep = p->devep;
+    uint8_t devep = p->ep->nr;
 
     /* protect data transfers from SIGALRM signal */
     sigemptyset(&new_mask);
diff --git a/usb-linux.c b/usb-linux.c
index afb13c4..cf074ec 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -137,7 +137,7 @@ static int usb_host_usbfs_type(USBHostDevice *s, USBPacket *p)
         [USB_ENDPOINT_XFER_BULK]    = USBDEVFS_URB_TYPE_BULK,
         [USB_ENDPOINT_XFER_INT]     = USBDEVFS_URB_TYPE_INTERRUPT,
     };
-    uint8_t type = usb_ep_get_type(&s->dev, p->pid, p->devep);
+    uint8_t type = p->ep->type;
     assert(type < ARRAY_SIZE(usbfs));
     return usbfs[type];
 }
@@ -360,7 +360,7 @@ static void async_complete(void *opaque)
                 break;
 
             case -EPIPE:
-                set_halt(s, p->pid, p->devep);
+                set_halt(s, p->pid, p->ep->nr);
                 p->result = USB_RET_STALL;
                 break;
 
@@ -733,16 +733,16 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
     int i, j, ret, max_packet_size, offset, len = 0;
     uint8_t *buf;
 
-    max_packet_size = usb_ep_get_max_packet_size(&s->dev, p->pid, p->devep);
+    max_packet_size = p->ep->max_packet_size;
     if (max_packet_size == 0)
         return USB_RET_NAK;
 
-    aurb = get_iso_urb(s, p->pid, p->devep);
+    aurb = get_iso_urb(s, p->pid, p->ep->nr);
     if (!aurb) {
-        aurb = usb_host_alloc_iso(s, p->pid, p->devep);
+        aurb = usb_host_alloc_iso(s, p->pid, p->ep->nr);
     }
 
-    i = get_iso_urb_idx(s, p->pid, p->devep);
+    i = get_iso_urb_idx(s, p->pid, p->ep->nr);
     j = aurb[i].iso_frame_idx;
     if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
         if (in) {
@@ -769,7 +769,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
             }
         } else {
             len = p->iov.size;
-            offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->pid, p->devep);
+            offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->pid, p->ep->nr);
 
             /* Check the frame fits */
             if (len > max_packet_size) {
@@ -781,27 +781,27 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
             usb_packet_copy(p, aurb[i].urb.buffer + offset, len);
             aurb[i].urb.iso_frame_desc[j].length = len;
             offset += len;
-            set_iso_buffer_used(s, p->pid, p->devep, offset);
+            set_iso_buffer_used(s, p->pid, p->ep->nr, offset);
 
             /* Start the stream once we have buffered enough data */
-            if (!is_iso_started(s, p->pid, p->devep) && i == 1 && j == 8) {
-                set_iso_started(s, p->pid, p->devep);
+            if (!is_iso_started(s, p->pid, p->ep->nr) && i == 1 && j == 8) {
+                set_iso_started(s, p->pid, p->ep->nr);
             }
         }
         aurb[i].iso_frame_idx++;
         if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
             i = (i + 1) % s->iso_urb_count;
-            set_iso_urb_idx(s, p->pid, p->devep, i);
+            set_iso_urb_idx(s, p->pid, p->ep->nr, i);
         }
     } else {
         if (in) {
-            set_iso_started(s, p->pid, p->devep);
+            set_iso_started(s, p->pid, p->ep->nr);
         } else {
             DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
         }
     }
 
-    if (is_iso_started(s, p->pid, p->devep)) {
+    if (is_iso_started(s, p->pid, p->ep->nr)) {
         /* (Re)-submit all fully consumed / filled urbs */
         for (i = 0; i < s->iso_urb_count; i++) {
             if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
@@ -821,7 +821,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
                     break;
                 }
                 aurb[i].iso_frame_idx = -1;
-                change_iso_inflight(s, p->pid, p->devep, 1);
+                change_iso_inflight(s, p->pid, p->ep->nr, 1);
             }
         }
     }
@@ -840,20 +840,20 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
 
     trace_usb_host_req_data(s->bus_num, s->addr,
                             p->pid == USB_TOKEN_IN,
-                            p->devep, p->iov.size);
+                            p->ep->nr, p->iov.size);
 
-    if (!is_valid(s, p->pid, p->devep)) {
+    if (!is_valid(s, p->pid, p->ep->nr)) {
         trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
         return USB_RET_NAK;
     }
 
     if (p->pid == USB_TOKEN_IN) {
-        ep = p->devep | 0x80;
+        ep = p->ep->nr | 0x80;
     } else {
-        ep = p->devep;
+        ep = p->ep->nr;
     }
 
-    if (is_halted(s, p->pid, p->devep)) {
+    if (is_halted(s, p->pid, p->ep->nr)) {
         unsigned int arg = ep;
         ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
         if (ret < 0) {
@@ -861,10 +861,10 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
             trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
             return USB_RET_NAK;
         }
-        clear_halt(s, p->pid, p->devep);
+        clear_halt(s, p->pid, p->ep->nr);
     }
 
-    if (is_isoc(s, p->pid, p->devep)) {
+    if (is_isoc(s, p->pid, p->ep->nr)) {
         return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
     }
 
@@ -1057,7 +1057,7 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
     urb = &aurb->urb;
 
     urb->type     = USBDEVFS_URB_TYPE_CONTROL;
-    urb->endpoint = p->devep;
+    urb->endpoint = p->ep->nr;
 
     urb->buffer        = &dev->setup_buf;
     urb->buffer_length = length + 8;
diff --git a/usb-redir.c b/usb-redir.c
index d2769a8..15e2b12 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -610,7 +610,7 @@ static int usbredir_handle_data(USBDevice *udev, USBPacket *p)
     USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
     uint8_t ep;
 
-    ep = p->devep;
+    ep = p->ep->nr;
     if (p->pid == USB_TOKEN_IN) {
         ep |= USB_DIR_IN;
     }
commit 63095ab54c1ce554b1fc825fc678394ccb129e5b
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Jan 12 13:24:22 2012 +0100

    usb: add USBEndpoint->{nr,pid}
    
    Add a "nr" and "pid" fields to USBEndpoint so you can easily figure the
    endpoint number and direction of any given endpoint.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb.c b/hw/usb.c
index 8584db0..8bd1222 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -402,10 +402,15 @@ void usb_ep_init(USBDevice *dev)
 {
     int ep;
 
+    dev->ep_ctl.nr = 0;
     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].nr = ep + 1;
+        dev->ep_out[ep].nr = ep + 1;
+        dev->ep_in[ep].pid = USB_TOKEN_IN;
+        dev->ep_out[ep].pid = USB_TOKEN_OUT;
         dev->ep_in[ep].type = USB_ENDPOINT_XFER_INVALID;
         dev->ep_out[ep].type = USB_ENDPOINT_XFER_INVALID;
         dev->ep_in[ep].ifnum = 0;
diff --git a/hw/usb.h b/hw/usb.h
index 4e878d3..1e629af 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -171,6 +171,8 @@ struct USBDescString {
 #define USB_MAX_INTERFACES 16
 
 struct USBEndpoint {
+    uint8_t nr;
+    uint8_t pid;
     uint8_t type;
     uint8_t ifnum;
     int max_packet_size;
commit f53c398aa603cea135ee58fd15249aeff7b9c7ea
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Jan 12 12:51:48 2012 +0100

    usb: USBPacket: add status, rename owner -> ep
    
    Add enum to track the status of USBPackets, use that instead of the
    owner pointer to figure whenever a usb packet is currently in flight
    or not.  Add some more packet status sanity checks.  Also rename the
    USBEndpoint pointer from "owner" to "ep".
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 8f7b3c4..f0213ad 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -715,8 +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 == NULL ||
-            q->packet.owner->dev != dev) {
+        if (!usb_packet_is_inflight(&q->packet) ||
+            q->packet.ep->dev != dev) {
             continue;
         }
         ehci_free_queue(q);
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index ecac631..f4e52f1 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -811,8 +811,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 == NULL ||
-                s->ep[ep].packey[dir].p.owner->dev != dev) {
+            if (!usb_packet_is_inflight(&s->ep[ep].packey[dir].p) ||
+                s->ep[ep].packey[dir].p.ep->dev != dev) {
                 continue;
             }
             usb_cancel_packet(&s->ep[ep].packey[dir].p);
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index ba854c7..8a8f3bc 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1709,8 +1709,8 @@ 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 != NULL &&
-        ohci->usb_packet.owner->dev == dev) {
+        usb_packet_is_inflight(&ohci->usb_packet) &&
+        ohci->usb_packet.ep->dev == dev) {
         usb_cancel_packet(&ohci->usb_packet);
         ohci->async_td = 0;
     }
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index a1f597a..ef08145 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -236,8 +236,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 == NULL ||
-            curr->packet.owner->dev != dev) {
+        if (!usb_packet_is_inflight(&curr->packet) ||
+            curr->packet.ep->dev != dev) {
             continue;
         }
         uhci_async_unlink(s, curr);
diff --git a/hw/usb.c b/hw/usb.c
index 91107f9..8584db0 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -291,7 +291,7 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
     }
     assert(dev->addr == p->devaddr);
     assert(dev->state == USB_STATE_DEFAULT);
-    assert(p->owner == NULL);
+    assert(p->state == USB_PACKET_SETUP);
 
     if (p->devep == 0) {
         /* control pipe */
@@ -315,7 +315,8 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
     }
 
     if (ret == USB_RET_ASYNC) {
-        p->owner = usb_ep_get(dev, p->pid, p->devep);
+        p->ep = usb_ep_get(dev, p->pid, p->devep);
+        p->state = USB_PACKET_ASYNC;
     }
     return ret;
 }
@@ -325,8 +326,8 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
    handle_packet. */
 void usb_packet_complete(USBDevice *dev, USBPacket *p)
 {
-    assert(p->owner != NULL);
-    p->owner = NULL;
+    assert(p->state == USB_PACKET_ASYNC);
+    p->state = USB_PACKET_COMPLETE;
     dev->port->ops->complete(dev->port, p);
 }
 
@@ -335,9 +336,9 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
    completed.  */
 void usb_cancel_packet(USBPacket * p)
 {
-    assert(p->owner != NULL);
-    usb_device_cancel_packet(p->owner->dev, p);
-    p->owner = NULL;
+    assert(p->state == USB_PACKET_ASYNC);
+    p->state = USB_PACKET_CANCELED;
+    usb_device_cancel_packet(p->ep->dev, p);
 }
 
 
@@ -348,6 +349,8 @@ void usb_packet_init(USBPacket *p)
 
 void usb_packet_setup(USBPacket *p, int pid, uint8_t addr, uint8_t ep)
 {
+    assert(!usb_packet_is_inflight(p));
+    p->state = USB_PACKET_SETUP;
     p->pid = pid;
     p->devaddr = addr;
     p->devep = ep;
@@ -391,6 +394,7 @@ void usb_packet_skip(USBPacket *p, size_t bytes)
 
 void usb_packet_cleanup(USBPacket *p)
 {
+    assert(!usb_packet_is_inflight(p));
     qemu_iovec_destroy(&p->iov);
 }
 
diff --git a/hw/usb.h b/hw/usb.h
index 294c33d..4e878d3 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -289,8 +289,7 @@ typedef struct USBPortOps {
     void (*wakeup)(USBPort *port);
     /*
      * Note that port->dev will be different then the device from which
-     * the packet originated when a hub is involved, if you want the orginating
-     * device use p->owner
+     * the packet originated when a hub is involved.
      */
     void (*complete)(USBPort *port, USBPacket *p);
 } USBPortOps;
@@ -309,15 +308,24 @@ struct USBPort {
 typedef void USBCallback(USBPacket * packet, void *opaque);
 
 /* Structure used to hold information about an active USB packet.  */
+typedef enum USBPacketState {
+    USB_PACKET_UNDEFINED = 0,
+    USB_PACKET_SETUP,
+    USB_PACKET_ASYNC,
+    USB_PACKET_COMPLETE,
+    USB_PACKET_CANCELED,
+} USBPacketState;
+
 struct USBPacket {
     /* Data fields for use by the driver.  */
     int pid;
     uint8_t devaddr;
     uint8_t devep;
+    USBEndpoint *ep;
     QEMUIOVector iov;
     int result; /* transfer length or USB_RET_* status code */
     /* Internal use by the USB layer.  */
-    USBEndpoint *owner;
+    USBPacketState state;
 };
 
 void usb_packet_init(USBPacket *p);
@@ -329,6 +337,11 @@ void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes);
 void usb_packet_skip(USBPacket *p, size_t bytes);
 void usb_packet_cleanup(USBPacket *p);
 
+static inline bool usb_packet_is_inflight(USBPacket *p)
+{
+    return p->state == USB_PACKET_ASYNC;
+}
+
 USBDevice *usb_find_device(USBPort *port, uint8_t addr);
 
 int usb_handle_packet(USBDevice *dev, USBPacket *p);
commit 1977f93dacf60466cd23b562ae498446b77d3b48
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Jan 11 12:14:02 2012 +0100

    usb: fold usb_generic_handle_packet into usb_handle_packet
    
    There is no reason to have a separate usb_generic_handle_packet function
    any more, fold it into usb_handle_packet().  Also call the do_token_*
    functions which handle control transfer emulation for control pipe
    packets only.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb.c b/hw/usb.c
index 638a339..91107f9 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -140,8 +140,7 @@ static int do_token_in(USBDevice *s, USBPacket *p)
     int request, value, index;
     int ret = 0;
 
-    if (p->devep != 0)
-        return usb_device_handle_data(s, p);
+    assert(p->devep == 0);
 
     request = (s->setup_buf[0] << 8) | s->setup_buf[1];
     value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
@@ -187,8 +186,7 @@ static int do_token_in(USBDevice *s, USBPacket *p)
 
 static int do_token_out(USBDevice *s, USBPacket *p)
 {
-    if (p->devep != 0)
-        return usb_device_handle_data(s, p);
+    assert(p->devep == 0);
 
     switch(s->setup_state) {
     case SETUP_STATE_ACK:
@@ -221,33 +219,6 @@ static int do_token_out(USBDevice *s, USBPacket *p)
     }
 }
 
-/*
- * Generic packet handler.
- * Called by the HC (host controller).
- *
- * Returns length of the transaction or one of the USB_RET_XXX codes.
- */
-static int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
-{
-    /* Rest of the PIDs must match our address */
-    if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
-        return USB_RET_NODEV;
-
-    switch (p->pid) {
-    case USB_TOKEN_SETUP:
-        return do_token_setup(s, p);
-
-    case USB_TOKEN_IN:
-        return do_token_in(s, p);
-
-    case USB_TOKEN_OUT:
-        return do_token_out(s, p);
- 
-    default:
-        return USB_RET_STALL;
-    }
-}
-
 /* ctrl complete function for devices which use usb_generic_handle_packet and
    may return USB_RET_ASYNC from their handle_control callback. Device code
    which does this *must* call this function instead of the normal
@@ -319,9 +290,30 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
         return USB_RET_NODEV;
     }
     assert(dev->addr == p->devaddr);
-
+    assert(dev->state == USB_STATE_DEFAULT);
     assert(p->owner == NULL);
-    ret = usb_generic_handle_packet(dev, p);
+
+    if (p->devep == 0) {
+        /* control pipe */
+        switch (p->pid) {
+        case USB_TOKEN_SETUP:
+            ret = do_token_setup(dev, p);
+            break;
+        case USB_TOKEN_IN:
+            ret = do_token_in(dev, p);
+            break;
+        case USB_TOKEN_OUT:
+            ret = do_token_out(dev, p);
+            break;
+        default:
+            ret = USB_RET_STALL;
+            break;
+        }
+    } else {
+        /* data pipe */
+        ret = usb_device_handle_data(dev, p);
+    }
+
     if (ret == USB_RET_ASYNC) {
         p->owner = usb_ep_get(dev, p->pid, p->devep);
     }
commit 7f74a56b1416a759c1da0a280e99242662f350c5
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Jan 11 11:16:20 2012 +0100

    usb: kill handle_packet callback
    
    All drivers except usb-hub use usb_generic_handle_packet.  The only
    reason the usb hub has its own function is that it used to be called
    with packets which are intended for downstream devices.  With the new,
    separate device lookup step this doesn't happen any more, so the need
    for a different handle_packet callback is gone.
    
    So we can kill the handle_packet callback and just call
    usb_generic_handle_packet directly.  The special hub handling in
    usb_handle_packet() can go away for the same reason.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-audio.c b/hw/usb-audio.c
index cd589b7..a4ea0b0 100644
--- a/hw/usb-audio.c
+++ b/hw/usb-audio.c
@@ -691,7 +691,6 @@ static void usb_audio_class_init(ObjectClass *klass, void *data)
     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;
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index 90c3b0e..58b247e 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -535,7 +535,6 @@ static void usb_bt_class_initfn(ObjectClass *klass, void *data)
     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;
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index 5c05ed5..e907d0d 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -91,15 +91,6 @@ static void usb_device_handle_destroy(USBDevice *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);
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index 881da30..b3bcfeb 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -1320,7 +1320,6 @@ static void ccid_class_initfn(ObjectClass *klass, void *data)
     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;
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 3c4e45d..c648980 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -557,7 +557,6 @@ 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;
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index bd7641c..2256256 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -455,44 +455,6 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
     return ret;
 }
 
-static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p)
-{
-    USBHubPort *port;
-    USBDevice *dev;
-    int i, ret;
-
-    for(i = 0; i < NUM_PORTS; i++) {
-        port = &s->ports[i];
-        dev = port->port.dev;
-        if (dev && dev->attached && (port->wPortStatus & PORT_STAT_ENABLE)) {
-            ret = usb_handle_packet(dev, p);
-            if (ret != USB_RET_NODEV) {
-                return ret;
-            }
-        }
-    }
-    return USB_RET_NODEV;
-}
-
-static int usb_hub_handle_packet(USBDevice *dev, USBPacket *p)
-{
-    USBHubState *s = (USBHubState *)dev;
-
-#if defined(DEBUG) && 0
-    printf("usb_hub: pid=0x%x\n", pid);
-#endif
-    if (dev->state == USB_STATE_DEFAULT &&
-        dev->addr != 0 &&
-        p->devaddr != dev->addr &&
-        (p->pid == USB_TOKEN_SETUP ||
-         p->pid == USB_TOKEN_OUT ||
-         p->pid == USB_TOKEN_IN)) {
-        /* broadcast the packet to the devices */
-        return usb_hub_broadcast_packet(s, p);
-    }
-    return usb_generic_handle_packet(dev, p);
-}
-
 static void usb_hub_handle_destroy(USBDevice *dev)
 {
     USBHubState *s = (USBHubState *)dev;
@@ -562,7 +524,6 @@ static void usb_hub_class_initfn(ObjectClass *klass, void *data)
     uc->product_desc   = "QEMU USB Hub";
     uc->usb_desc       = &desc_hub;
     uc->find_device    = usb_hub_find_device;
-    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;
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 6153376..c34cad5 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -651,7 +651,6 @@ static void usb_msd_class_initfn(ObjectClass *klass, void *data)
     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;
diff --git a/hw/usb-net.c b/hw/usb-net.c
index e211141..f00e854 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1398,7 +1398,6 @@ static void usb_net_class_initfn(ObjectClass *klass, void *data)
     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;
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index c2cb6d2..cf83cf2 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -583,7 +583,6 @@ static void usb_serial_class_initfn(ObjectClass *klass, void *data)
     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;
@@ -612,7 +611,6 @@ static void usb_braille_class_initfn(ObjectClass *klass, void *data)
     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;
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 14de14d..46b8010 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -357,7 +357,6 @@ static void usb_wacom_class_init(ObjectClass *klass, void *data)
     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;
diff --git a/hw/usb.c b/hw/usb.c
index 9976f81..638a339 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -227,7 +227,7 @@ static int do_token_out(USBDevice *s, USBPacket *p)
  *
  * Returns length of the transaction or one of the USB_RET_XXX codes.
  */
-int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
+static int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
 {
     /* Rest of the PIDs must match our address */
     if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
@@ -318,18 +318,12 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
     if (dev == NULL) {
         return USB_RET_NODEV;
     }
+    assert(dev->addr == p->devaddr);
 
     assert(p->owner == NULL);
-    ret = usb_device_handle_packet(dev, p);
+    ret = usb_generic_handle_packet(dev, p);
     if (ret == USB_RET_ASYNC) {
-        if (p->owner == NULL) {
-            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
-             * to do.  Leave p->owner pointing to the device, not the
-             * hub. */;
-        }
+        p->owner = usb_ep_get(dev, p->pid, p->devep);
     }
     return ret;
 }
@@ -339,7 +333,6 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
    handle_packet. */
 void usb_packet_complete(USBDevice *dev, USBPacket *p)
 {
-    /* Note: p->owner != dev is possible in case dev is a hub */
     assert(p->owner != NULL);
     p->owner = NULL;
     dev->port->ops->complete(dev->port, p);
diff --git a/hw/usb.h b/hw/usb.h
index 1beb4b3..294c33d 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -235,15 +235,6 @@ typedef struct USBDeviceClass {
     USBDevice *(*find_device)(USBDevice *dev, uint8_t addr);
 
     /*
-     * Process USB packet.
-     * Called by the HC (Host Controller).
-     *
-     * Returns length of the transaction
-     * or one of the USB_RET_XXX codes.
-     */
-    int (*handle_packet)(USBDevice *dev, USBPacket *p);
-
-    /*
      * Called when a packet is canceled.
      */
     void (*cancel_packet)(USBDevice *dev, USBPacket *p);
@@ -360,7 +351,6 @@ void usb_detach(USBPort *port);
 void usb_port_reset(USBPort *port);
 void usb_device_reset(USBDevice *dev);
 void usb_wakeup(USBDevice *dev);
-int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
 void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
 int set_usb_string(uint8_t *buf, const char *str);
 
@@ -456,8 +446,6 @@ extern const VMStateDescription vmstate_usb_device;
 
 USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr);
 
-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);
diff --git a/usb-bsd.c b/usb-bsd.c
index fc722b3..ca9a1bd 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -403,7 +403,6 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data)
 
     uc->product_desc   = "USB Host Device";
     uc->init           = usb_host_initfn;
-    uc->handle_packet  = usb_generic_handle_packet;
     uc->handle_reset   = usb_host_handle_reset;
     uc->handle_control = usb_host_handle_control;
     uc->handle_data    = usb_host_handle_data;
diff --git a/usb-linux.c b/usb-linux.c
index e7fc9ec..afb13c4 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -1419,7 +1419,6 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data)
 
     uc->init           = usb_host_initfn;
     uc->product_desc   = "USB Host Device";
-    uc->handle_packet  = usb_generic_handle_packet;
     uc->cancel_packet  = usb_host_async_cancel;
     uc->handle_data    = usb_host_handle_data;
     uc->handle_control = usb_host_handle_control;
diff --git a/usb-redir.c b/usb-redir.c
index 0a92951..d2769a8 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -1424,7 +1424,6 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data)
     uc->init           = usbredir_initfn;
     uc->product_desc   = "USB Redirection Device";
     uc->handle_destroy = usbredir_handle_destroy;
-    uc->handle_packet  = usb_generic_handle_packet;
     uc->cancel_packet  = usbredir_cancel_packet;
     uc->handle_reset   = usbredir_handle_reset;
     uc->handle_data    = usbredir_handle_data;
commit e74495e3ade61ceabc5a00713900d8295e4042f4
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jan 10 18:05:22 2012 +0100

    usb-xhci: switch to usb_find_device()
    
    Switch over xHCI to use the new usb_find_device()
    function for device lookup.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c
index 7028338..aa236c9 100644
--- a/hw/usb-xhci.c
+++ b/hw/usb-xhci.c
@@ -1385,6 +1385,14 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret)
     return 0;
 }
 
+static USBDevice *xhci_find_device(XHCIPort *port, uint8_t addr)
+{
+    if (!(port->portsc & PORTSC_PED)) {
+        return NULL;
+    }
+    return usb_find_device(&port->port, addr);
+}
+
 static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
 {
     XHCITRB *trb_setup, *trb_status;
@@ -1444,7 +1452,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
     xfer->data_length = wLength;
 
     port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1];
-    dev = port->port.dev;
+    dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr);
     if (!dev) {
         fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid,
                 xhci->slots[xfer->slotid-1].port);
@@ -1502,7 +1510,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
     }
 
     port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1];
-    dev = port->port.dev;
+    dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr);
     if (!dev) {
         fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid,
                 xhci->slots[xfer->slotid-1].port);
commit 87e043f17e9b3781b3c29c02ff32abc23ac15708
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jan 10 17:59:33 2012 +0100

    usb-musb: switch to usb_find_device()
    
    Switch over musb to use the new usb_find_device()
    function for device lookup.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index c2753c9..ecac631 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -605,6 +605,7 @@ static int musb_timeout(int ttype, int speed, int val)
 static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
                 int epnum, int pid, int len, USBCallback cb, int dir)
 {
+    USBDevice *dev;
     int ret;
     int idx = epnum && dir;
     int ttype;
@@ -628,10 +629,8 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
     ep->packey[dir].ep = ep;
     ep->packey[dir].dir = dir;
 
-    if (s->port.dev)
-        ret = usb_handle_packet(s->port.dev, &ep->packey[dir].p);
-    else
-        ret = USB_RET_NODEV;
+    dev = usb_find_device(&s->port, ep->packey[dir].p.devaddr);
+    ret = usb_handle_packet(dev, &ep->packey[dir].p);
 
     if (ret == USB_RET_ASYNC) {
         ep->status[dir] = len;
commit 993048bb6bf6b74bbf6b7dae8e7c2db523cfcecf
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jan 10 17:56:17 2012 +0100

    usb-ohci: switch to usb_find_device()
    
    Switch over OHCI to use the new usb_find_device()
    function for device lookup.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 70f0f08..ba854c7 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -408,6 +408,23 @@ static void ohci_child_detach(USBPort *port1, USBDevice *child)
     ohci_async_cancel_device(s, child);
 }
 
+static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr)
+{
+    USBDevice *dev;
+    int i;
+
+    for (i = 0; i < ohci->num_ports; i++) {
+        if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) {
+            continue;
+        }
+        dev = usb_find_device(&ohci->rhport[i].port, addr);
+        if (dev != NULL) {
+            return dev;
+        }
+    }
+    return NULL;
+}
+
 /* Reset the controller */
 static void ohci_reset(void *opaque)
 {
@@ -779,20 +796,12 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
     if (completion) {
         ret = ohci->usb_packet.result;
     } else {
-        ret = USB_RET_NODEV;
-        for (i = 0; i < ohci->num_ports; i++) {
-            dev = ohci->rhport[i].port.dev;
-            if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0)
-                continue;
-            usb_packet_setup(&ohci->usb_packet, pid,
-                             OHCI_BM(ed->flags, ED_FA),
-                             OHCI_BM(ed->flags, ED_EN));
-            usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
-            ret = usb_handle_packet(dev, &ohci->usb_packet);
-            if (ret != USB_RET_NODEV)
-                break;
-        }
-    
+        usb_packet_setup(&ohci->usb_packet, pid,
+                         OHCI_BM(ed->flags, ED_FA),
+                         OHCI_BM(ed->flags, ED_EN));
+        usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
+        dev = ohci_find_device(ohci, ohci->usb_packet.devaddr);
+        ret = usb_handle_packet(dev, &ohci->usb_packet);
         if (ret == USB_RET_ASYNC) {
             return 1;
         }
@@ -972,31 +981,23 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
         ohci->async_td = 0;
         ohci->async_complete = 0;
     } else {
-        ret = USB_RET_NODEV;
-        for (i = 0; i < ohci->num_ports; i++) {
-            dev = ohci->rhport[i].port.dev;
-            if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0)
-                continue;
-
-            if (ohci->async_td) {
-                /* ??? The hardware should allow one active packet per
-                   endpoint.  We only allow one active packet per controller.
-                   This should be sufficient as long as devices respond in a
-                   timely manner.
-                 */
+        if (ohci->async_td) {
+            /* ??? The hardware should allow one active packet per
+               endpoint.  We only allow one active packet per controller.
+               This should be sufficient as long as devices respond in a
+               timely manner.
+            */
 #ifdef DEBUG_PACKET
-                DPRINTF("Too many pending packets\n");
+            DPRINTF("Too many pending packets\n");
 #endif
-                return 1;
-            }
-            usb_packet_setup(&ohci->usb_packet, pid,
-                             OHCI_BM(ed->flags, ED_FA),
-                             OHCI_BM(ed->flags, ED_EN));
-            usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
-            ret = usb_handle_packet(dev, &ohci->usb_packet);
-            if (ret != USB_RET_NODEV)
-                break;
+            return 1;
         }
+        usb_packet_setup(&ohci->usb_packet, pid,
+                         OHCI_BM(ed->flags, ED_FA),
+                         OHCI_BM(ed->flags, ED_EN));
+        usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
+        dev = ohci_find_device(ohci, ohci->usb_packet.devaddr);
+        ret = usb_handle_packet(dev, &ohci->usb_packet);
 #ifdef DEBUG_PACKET
         DPRINTF("ret=%d\n", ret);
 #endif
commit 828143c621d8fd1030b5fd07d7ed340b82a5b763
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jan 10 17:46:15 2012 +0100

    usb-ehci: switch to usb_find_device()
    
    Switch over EHCI to use the new usb_find_device()
    function for device lookup.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 487214d..8f7b3c4 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -850,6 +850,26 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[],
     return 0;
 }
 
+static USBDevice *ehci_find_device(EHCIState *ehci, uint8_t addr)
+{
+    USBDevice *dev;
+    USBPort *port;
+    int i;
+
+    for (i = 0; i < NB_PORTS; i++) {
+        port = &ehci->ports[i];
+        if (!(ehci->portsc[i] & PORTSC_PED)) {
+            DPRINTF("Port %d not enabled\n", i);
+            continue;
+        }
+        dev = usb_find_device(port, addr);
+        if (dev != NULL) {
+            return dev;
+        }
+    }
+    return NULL;
+}
+
 /* 4.1 host controller initialization */
 static void ehci_reset(void *opaque)
 {
@@ -1336,10 +1356,8 @@ err:
 
 static int ehci_execute(EHCIQueue *q)
 {
-    USBPort *port;
     USBDevice *dev;
     int ret;
-    int i;
     int endp;
     int devadr;
 
@@ -1375,27 +1393,12 @@ static int ehci_execute(EHCIQueue *q)
     usb_packet_map(&q->packet, &q->sgl);
 
     // TO-DO: associating device with ehci port
-    for(i = 0; i < NB_PORTS; i++) {
-        port = &q->ehci->ports[i];
-        dev = port->dev;
-
-        if (!(q->ehci->portsc[i] &(PORTSC_CONNECT))) {
-            DPRINTF("Port %d, no exec, not connected(%08X)\n",
-                    i, q->ehci->portsc[i]);
-            continue;
-        }
-
-        ret = usb_handle_packet(dev, &q->packet);
-
-        DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd "
-                "(total %d) endp %x ret %d\n",
-                q->qhaddr, q->qh.next, q->qtdaddr, q->pid,
-                q->packet.iov.size, q->tbytes, endp, ret);
-
-        if (ret != USB_RET_NODEV) {
-            break;
-        }
-    }
+    dev = ehci_find_device(q->ehci, q->packet.devaddr);
+    ret = usb_handle_packet(dev, &q->packet);
+    DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd "
+            "(total %d) endp %x ret %d\n",
+            q->qhaddr, q->qh.next, q->qtdaddr, q->pid,
+            q->packet.iov.size, q->tbytes, endp, ret);
 
     if (ret > BUFF_SIZE) {
         fprintf(stderr, "ret from usb_handle_packet > BUFF_SIZE\n");
@@ -1411,10 +1414,9 @@ static int ehci_execute(EHCIQueue *q)
 static int ehci_process_itd(EHCIState *ehci,
                             EHCIitd *itd)
 {
-    USBPort *port;
     USBDevice *dev;
     int ret;
-    uint32_t i, j, len, pid, dir, devaddr, endp;
+    uint32_t i, len, pid, dir, devaddr, endp;
     uint32_t pg, off, ptr1, ptr2, max, mult;
 
     dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
@@ -1455,21 +1457,8 @@ static int ehci_process_itd(EHCIState *ehci,
             usb_packet_setup(&ehci->ipacket, pid, devaddr, endp);
             usb_packet_map(&ehci->ipacket, &ehci->isgl);
 
-            ret = USB_RET_NODEV;
-            for (j = 0; j < NB_PORTS; j++) {
-                port = &ehci->ports[j];
-                dev = port->dev;
-
-                if (!(ehci->portsc[j] &(PORTSC_CONNECT))) {
-                    continue;
-                }
-
-                ret = usb_handle_packet(dev, &ehci->ipacket);
-
-                if (ret != USB_RET_NODEV) {
-                    break;
-                }
-            }
+            dev = ehci_find_device(ehci, ehci->ipacket.devaddr);
+            ret = usb_handle_packet(dev, &ehci->ipacket);
 
             usb_packet_unmap(&ehci->ipacket);
             qemu_sglist_destroy(&ehci->isgl);
commit 461700c1dc006600d7a955ee67184ced6084fd19
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jan 10 17:34:24 2012 +0100

    usb-uhci: switch to usb_find_device()
    
    Switch over UHCI to use the new usb_find_device()
    function for device lookup.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 407e0f3..a1f597a 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -94,15 +94,6 @@ static const char *pid2str(int pid)
 #define DPRINTF(...)
 #endif
 
-#ifdef DEBUG_DUMP_DATA
-static void dump_data(USBPacket *p, int ret)
-{
-    iov_hexdump(p->iov.iov, p->iov.niov, stderr, "uhci", ret);
-}
-#else
-static void dump_data(USBPacket *p, int ret) {}
-#endif
-
 typedef struct UHCIState UHCIState;
 
 /* 
@@ -643,30 +634,22 @@ static void uhci_wakeup(USBPort *port1)
     }
 }
 
-static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
+static USBDevice *uhci_find_device(UHCIState *s, uint8_t addr)
 {
-    int i, ret;
-
-    DPRINTF("uhci: packet enter. pid %s addr 0x%02x ep %d len %zd\n",
-           pid2str(p->pid), p->devaddr, p->devep, p->iov.size);
-    if (p->pid == USB_TOKEN_OUT || p->pid == USB_TOKEN_SETUP)
-        dump_data(p, 0);
+    USBDevice *dev;
+    int i;
 
-    ret = USB_RET_NODEV;
-    for (i = 0; i < NB_PORTS && ret == USB_RET_NODEV; i++) {
+    for (i = 0; i < NB_PORTS; i++) {
         UHCIPort *port = &s->ports[i];
-        USBDevice *dev = port->port.dev;
-
-        if (dev && dev->attached && (port->ctrl & UHCI_PORT_EN)) {
-            ret = usb_handle_packet(dev, p);
+        if (!(port->ctrl & UHCI_PORT_EN)) {
+            continue;
+        }
+        dev = usb_find_device(&port->port, addr);
+        if (dev != NULL) {
+            return dev;
         }
     }
-
-    DPRINTF("uhci: packet exit. ret %d len %zd\n", ret, p->iov.size);
-    if (p->pid == USB_TOKEN_IN && ret > 0)
-        dump_data(p, ret);
-
-    return ret;
+    return NULL;
 }
 
 static void uhci_async_complete(USBPort *port, USBPacket *packet);
@@ -830,13 +813,15 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
     switch(pid) {
     case USB_TOKEN_OUT:
     case USB_TOKEN_SETUP:
-        len = uhci_broadcast_packet(s, &async->packet);
+        len = usb_handle_packet(uhci_find_device(s, async->packet.devaddr),
+                                &async->packet);
         if (len >= 0)
             len = max_len;
         break;
 
     case USB_TOKEN_IN:
-        len = uhci_broadcast_packet(s, &async->packet);
+        len = usb_handle_packet(uhci_find_device(s, async->packet.devaddr),
+                                &async->packet);
         break;
 
     default:
commit 98861f512bbd8789bd7935a75316d3278be23a0a
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jan 10 17:33:02 2012 +0100

    usb: handle dev == NULL in usb_handle_packet()
    
    Allow passing in a NULL pointer, return USB_RET_NODEV in that case.
    Removes the burden to to a NULL pointer check from the callers.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb.c b/hw/usb.c
index bacdc81..9976f81 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -315,6 +315,10 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
 {
     int ret;
 
+    if (dev == NULL) {
+        return USB_RET_NODEV;
+    }
+
     assert(p->owner == NULL);
     ret = usb_device_handle_packet(dev, p);
     if (ret == USB_RET_ASYNC) {
commit 06c750888c57bdc374feaa097f6cbc720210b834
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jan 10 17:08:13 2012 +0100

    usb-hub: implement find_device
    
    Implement the find_device callback for the usb hub.  It'll loop over all
    ports, calling usb_find_device for all enabled ports until it finds a
    matching device.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 0f3b2dd..bd7641c 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -220,6 +220,26 @@ static void usb_hub_complete(USBPort *port, USBPacket *packet)
     s->dev.port->ops->complete(s->dev.port, packet);
 }
 
+static USBDevice *usb_hub_find_device(USBDevice *dev, uint8_t addr)
+{
+    USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
+    USBHubPort *port;
+    USBDevice *downstream;
+    int i;
+
+    for (i = 0; i < NUM_PORTS; i++) {
+        port = &s->ports[i];
+        if (!(port->wPortStatus & PORT_STAT_ENABLE)) {
+            continue;
+        }
+        downstream = usb_find_device(&port->port, addr);
+        if (downstream != NULL) {
+            return downstream;
+        }
+    }
+    return NULL;
+}
+
 static void usb_hub_handle_reset(USBDevice *dev)
 {
     USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
@@ -541,6 +561,7 @@ static void usb_hub_class_initfn(ObjectClass *klass, void *data)
     uc->init           = usb_hub_initfn;
     uc->product_desc   = "QEMU USB Hub";
     uc->usb_desc       = &desc_hub;
+    uc->find_device    = usb_hub_find_device;
     uc->handle_packet  = usb_hub_handle_packet;
     uc->handle_reset   = usb_hub_handle_reset;
     uc->handle_control = usb_hub_handle_control;
commit 73796fe6228ae1e294b4946c6c90337141cacc42
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jan 10 16:59:28 2012 +0100

    usb: add usb_find_device()
    
    Add usb_find_device().  This function will check whenever a device with
    a specific address is connected to the specified port.  Usually this
    will just check state and address of the device hooked up to the port,
    but in case of a hub it will ask the hub to check all hub ports for a
    matching device.
    
    This patch doesn't put the code into use yet, see the following patches
    for details.
    
    The master plan is to separate device lookup and packet processing.
    Right now the usb code simply walks all devices, calls
    usb_handle_packet() on each until one accepts the packet (by returning
    something different that USB_RET_NODEV).  I want to have a device lookup
    first, then call usb_handle_packet() once, for the device which actually
    processes the packet.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index b753834..5c05ed5 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -74,6 +74,15 @@ static int usb_device_init(USBDevice *dev)
     return 0;
 }
 
+USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr)
+{
+    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+    if (klass->find_device) {
+        return klass->find_device(dev, addr);
+    }
+    return NULL;
+}
+
 static void usb_device_handle_destroy(USBDevice *dev)
 {
     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
diff --git a/hw/usb.c b/hw/usb.c
index 0c26164..bacdc81 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -295,6 +295,19 @@ int set_usb_string(uint8_t *buf, const char *str)
     return q - buf;
 }
 
+USBDevice *usb_find_device(USBPort *port, uint8_t addr)
+{
+    USBDevice *dev = port->dev;
+
+    if (dev == NULL || !dev->attached || dev->state != USB_STATE_DEFAULT) {
+        return NULL;
+    }
+    if (dev->addr == addr) {
+        return dev;
+    }
+    return usb_device_find_device(dev, addr);
+}
+
 /* Hand over a packet to a device for processing.  Return value
    USB_RET_ASYNC indicates the processing isn't finished yet, the
    driver will call usb_packet_complete() when done processing it. */
diff --git a/hw/usb.h b/hw/usb.h
index 6127176..1beb4b3 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -229,6 +229,12 @@ typedef struct USBDeviceClass {
     int (*init)(USBDevice *dev);
 
     /*
+     * Walk (enabled) downstream ports, check for a matching device.
+     * Only hubs implement this.
+     */
+    USBDevice *(*find_device)(USBDevice *dev, uint8_t addr);
+
+    /*
      * Process USB packet.
      * Called by the HC (Host Controller).
      *
@@ -332,6 +338,8 @@ void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes);
 void usb_packet_skip(USBPacket *p, size_t bytes);
 void usb_packet_cleanup(USBPacket *p);
 
+USBDevice *usb_find_device(USBPort *port, uint8_t addr);
+
 int usb_handle_packet(USBDevice *dev, USBPacket *p);
 void usb_packet_complete(USBDevice *dev, USBPacket *p);
 void usb_cancel_packet(USBPacket * p);
@@ -446,6 +454,8 @@ extern const VMStateDescription vmstate_usb_device;
     .offset     = vmstate_offset_value(_state, _field, USBDevice),   \
 }
 
+USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr);
+
 int usb_device_handle_packet(USBDevice *dev, USBPacket *p);
 
 void usb_device_cancel_packet(USBDevice *dev, USBPacket *p);
commit 70fc20d4dc7c8990a508411db1ee441ae9ee5034
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jan 6 15:31:38 2012 +0100

    usb: kill usb_send_msg
    
    No users left.  Zap it.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb.c b/hw/usb.c
index c8e6be4..0c26164 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -295,19 +295,6 @@ int set_usb_string(uint8_t *buf, const char *str)
     return q - buf;
 }
 
-/* Send an internal message to a USB device.  */
-void usb_send_msg(USBDevice *dev, int msg)
-{
-    USBPacket p;
-    int ret;
-
-    memset(&p, 0, sizeof(p));
-    p.pid = msg;
-    ret = usb_handle_packet(dev, &p);
-    /* This _must_ be synchronous */
-    assert(ret != USB_RET_ASYNC);
-}
-
 /* Hand over a packet to a device for processing.  Return value
    USB_RET_ASYNC indicates the processing isn't finished yet, the
    driver will call usb_packet_complete() when done processing it. */
diff --git a/hw/usb.h b/hw/usb.h
index b56e812..6127176 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -355,7 +355,6 @@ void usb_wakeup(USBDevice *dev);
 int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
 void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
 int set_usb_string(uint8_t *buf, const char *str);
-void usb_send_msg(USBDevice *dev, int msg);
 
 /* usb-linux.c */
 USBDevice *usb_host_device_open(const char *devname);
commit d28f4e2d86317f7ef7398651e8a1d493e4bf8c88
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jan 6 15:23:10 2012 +0100

    usb: kill USB_MSG_RESET
    
    The USB subsystem pipes internal reset notifications through
    usb_handle_packet() with a special magic PID.  This indirection
    is a pretty pointless excercise as it ends up being handled by
    usb_generic_handle_packet anyway.
    
    Replace the USB_MSG_RESET with a usb_device_reset() function
    which can be called directly.  Also rename the existing usb_reset()
    function to usb_port_reset() to avoid confusion.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index cdd7415..487214d 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -888,7 +888,7 @@ static void ehci_reset(void *opaque)
         }
         if (devs[i] && devs[i]->attached) {
             usb_attach(&s->ports[i]);
-            usb_send_msg(devs[i], USB_MSG_RESET);
+            usb_device_reset(devs[i]);
         }
     }
     ehci_queues_rip_all(s);
@@ -987,7 +987,7 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
     if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
         trace_usb_ehci_port_reset(port, 0);
         if (dev && dev->attached) {
-            usb_reset(&s->ports[port]);
+            usb_port_reset(&s->ports[port]);
             *portsc &= ~PORTSC_CSC;
         }
 
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 956b020..0f3b2dd 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -305,7 +305,7 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
                 break;
             case PORT_RESET:
                 if (dev && dev->attached) {
-                    usb_send_msg(dev, USB_MSG_RESET);
+                    usb_device_reset(dev);
                     port->wPortChange |= PORT_STAT_C_RESET;
                     /* set enable bit */
                     port->wPortStatus |= PORT_STAT_ENABLE;
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 4f528d2..c2753c9 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -1310,7 +1310,7 @@ static void musb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value)
         s->power = (value & 0xef) | (s->power & 0x10);
         /* MGC_M_POWER_RESET is also read-only in Peripheral Mode */
         if ((value & MGC_M_POWER_RESET) && s->port.dev) {
-            usb_send_msg(s->port.dev, USB_MSG_RESET);
+            usb_device_reset(s->port.dev);
             /* Negotiate high-speed operation if MGC_M_POWER_HSENAB is set.  */
             if ((value & MGC_M_POWER_HSENAB) &&
                             s->port.dev->speed == USB_SPEED_HIGH)
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 425030f..70f0f08 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -449,7 +449,7 @@ static void ohci_reset(void *opaque)
         port = &ohci->rhport[i];
         port->ctrl = 0;
         if (port->port.dev && port->port.dev->attached) {
-            usb_reset(&port->port);
+            usb_port_reset(&port->port);
         }
       }
     if (ohci->async_td) {
@@ -1435,7 +1435,7 @@ static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val)
 
     if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) {
         DPRINTF("usb-ohci: port %d: RESET\n", portnum);
-        usb_send_msg(port->port.dev, USB_MSG_RESET);
+        usb_device_reset(port->port.dev);
         port->ctrl &= ~OHCI_PORT_PRS;
         /* ??? Should this also set OHCI_PORT_PESC.  */
         port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC;
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index e0c7dbb..407e0f3 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -342,7 +342,7 @@ static void uhci_reset(void *opaque)
         port = &s->ports[i];
         port->ctrl = 0x0080;
         if (port->port.dev && port->port.dev->attached) {
-            usb_reset(&port->port);
+            usb_port_reset(&port->port);
         }
     }
 
@@ -440,16 +440,12 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
         }
         if (val & UHCI_CMD_GRESET) {
             UHCIPort *port;
-            USBDevice *dev;
             int i;
 
             /* send reset on the USB bus */
             for(i = 0; i < NB_PORTS; i++) {
                 port = &s->ports[i];
-                dev = port->port.dev;
-                if (dev && dev->attached) {
-                    usb_send_msg(dev, USB_MSG_RESET);
-                }
+                usb_device_reset(port->port.dev);
             }
             uhci_reset(s);
             return;
@@ -491,7 +487,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
                 /* port reset */
                 if ( (val & UHCI_PORT_RESET) &&
                      !(port->ctrl & UHCI_PORT_RESET) ) {
-                    usb_send_msg(dev, USB_MSG_RESET);
+                    usb_device_reset(dev);
                 }
             }
             port->ctrl &= UHCI_PORT_READ_ONLY;
diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c
index 37e887c..7028338 100644
--- a/hw/usb-xhci.c
+++ b/hw/usb-xhci.c
@@ -2346,9 +2346,7 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val)
         /* 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);
-            }
+            usb_device_reset(xhci->ports[port].port.dev);
             portsc |= PORTSC_PRC | PORTSC_PED;
         }
         xhci->ports[port].portsc = portsc;
diff --git a/hw/usb.c b/hw/usb.c
index 800dd83..c8e6be4 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -49,14 +49,25 @@ void usb_detach(USBPort *port)
     dev->state = USB_STATE_NOTATTACHED;
 }
 
-void usb_reset(USBPort *port)
+void usb_port_reset(USBPort *port)
 {
     USBDevice *dev = port->dev;
 
     assert(dev != NULL);
     usb_detach(port);
     usb_attach(port);
-    usb_send_msg(dev, USB_MSG_RESET);
+    usb_device_reset(dev);
+}
+
+void usb_device_reset(USBDevice *dev)
+{
+    if (dev == NULL || !dev->attached) {
+        return;
+    }
+    dev->remote_wakeup = 0;
+    dev->addr = 0;
+    dev->state = USB_STATE_DEFAULT;
+    usb_device_handle_reset(dev);
 }
 
 void usb_wakeup(USBDevice *dev)
@@ -218,15 +229,6 @@ static int do_token_out(USBDevice *s, USBPacket *p)
  */
 int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
 {
-    switch(p->pid) {
-    case USB_MSG_RESET:
-        s->remote_wakeup = 0;
-        s->addr = 0;
-        s->state = USB_STATE_DEFAULT;
-        usb_device_handle_reset(s);
-        return 0;
-    }
-
     /* Rest of the PIDs must match our address */
     if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
         return USB_RET_NODEV;
diff --git a/hw/usb.h b/hw/usb.h
index 0bd9098..b56e812 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -39,9 +39,6 @@
 #define USB_TOKEN_IN    0x69 /* device -> host */
 #define USB_TOKEN_OUT   0xe1 /* host -> device */
 
-/* specific usb messages, also sent in the 'pid' parameter */
-#define USB_MSG_RESET    0x102
-
 #define USB_RET_NODEV  (-1)
 #define USB_RET_NAK    (-2)
 #define USB_RET_STALL  (-3)
@@ -352,7 +349,8 @@ 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);
+void usb_port_reset(USBPort *port);
+void usb_device_reset(USBDevice *dev);
 void usb_wakeup(USBDevice *dev);
 int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
 void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
commit d1f8b53618b3daa93a113ba02520cd1bd34c254b
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jan 6 15:13:34 2012 +0100

    usb: kill USB_MSG_{ATTACH,DETACH}
    
    The USB subsystem pipes internal attach/detach notifications through
    usb_handle_packet() with a special magic PID.  This indirection is a
    pretty pointless excercise as it ends up being handled by
    usb_generic_handle_packet anyway.  Remove it.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb.c b/hw/usb.c
index c3ff5b7..800dd83 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -35,7 +35,8 @@ void usb_attach(USBPort *port)
     assert(dev->attached);
     assert(dev->state == USB_STATE_NOTATTACHED);
     port->ops->attach(port);
-    usb_send_msg(dev, USB_MSG_ATTACH);
+    dev->state = USB_STATE_ATTACHED;
+    usb_device_handle_attach(dev);
 }
 
 void usb_detach(USBPort *port)
@@ -45,7 +46,7 @@ void usb_detach(USBPort *port)
     assert(dev != NULL);
     assert(dev->state != USB_STATE_NOTATTACHED);
     port->ops->detach(port);
-    usb_send_msg(dev, USB_MSG_DETACH);
+    dev->state = USB_STATE_NOTATTACHED;
 }
 
 void usb_reset(USBPort *port)
@@ -218,15 +219,6 @@ static int do_token_out(USBDevice *s, USBPacket *p)
 int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
 {
     switch(p->pid) {
-    case USB_MSG_ATTACH:
-        s->state = USB_STATE_ATTACHED;
-        usb_device_handle_attach(s);
-        return 0;
-
-    case USB_MSG_DETACH:
-        s->state = USB_STATE_NOTATTACHED;
-        return 0;
-
     case USB_MSG_RESET:
         s->remote_wakeup = 0;
         s->addr = 0;
diff --git a/hw/usb.h b/hw/usb.h
index 13e7c8e..0bd9098 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -40,8 +40,6 @@
 #define USB_TOKEN_OUT   0xe1 /* host -> device */
 
 /* specific usb messages, also sent in the 'pid' parameter */
-#define USB_MSG_ATTACH   0x100
-#define USB_MSG_DETACH   0x101
 #define USB_MSG_RESET    0x102
 
 #define USB_RET_NODEV  (-1)
commit 6af165892cf900291046f1d25f95416f379504c2
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Wed Jan 25 09:50:39 2012 +0100

    usb-redir: Add the posibility to filter out certain devices from redirecion
    
    This patch adds the posibility to filter out certain devices from redirecion.
    To use this pass the filter property to -device usb-redir.  The filter
    property takes a string consisting of filter rules, the format for a rule is:
    <class>:<vendor>:<product>:<version>:<allow>
    
    -1 can be used to allow any value for a field.
    
    Muliple rules can be concatonated using | as a separator. Note that if
    a device matches none of the passed in rules, redirecting it will not be
    allowed!
    
    Example:
    -device usb-redir,filter='-1:0x0781:0x5567:-1:0|0x08:-1:-1:-1:1'
    
    This example will deny the Sandisk Cruzer Blade being redirected, as it
    has a usb id of 0781:5567, it will allow any other usb mass storage devices,
    and it will deny any other devices (the default for devices not matching any
    of the rules.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/configure b/configure
index 763db24..68f9ee6 100755
--- a/configure
+++ b/configure
@@ -2584,7 +2584,7 @@ fi
 
 # check for usbredirparser for usb network redirection support
 if test "$usb_redir" != "no" ; then
-    if $pkg_config libusbredirparser >/dev/null 2>&1 ; then
+    if $pkg_config --atleast-version=0.3.3 libusbredirparser >/dev/null 2>&1 ; then
         usb_redir="yes"
         usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null)
         usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null)
diff --git a/usb-redir.c b/usb-redir.c
index 303292a..0a92951 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -34,6 +34,7 @@
 #include <sys/ioctl.h>
 #include <signal.h>
 #include <usbredirparser.h>
+#include <usbredirfilter.h>
 
 #include "hw/usb.h"
 
@@ -72,6 +73,7 @@ struct USBRedirDevice {
     /* Properties */
     CharDriverState *cs;
     uint8_t debug;
+    char *filter_str;
     /* Data passed from chardev the fd_read cb to the usbredirparser read cb */
     const uint8_t *read_buf;
     int read_buf_size;
@@ -84,6 +86,11 @@ struct USBRedirDevice {
     struct endp_data endpoint[MAX_ENDPOINTS];
     uint32_t packet_id;
     QTAILQ_HEAD(, AsyncURB) asyncq;
+    /* Data for device filtering */
+    struct usb_redir_device_connect_header device_info;
+    struct usb_redir_interface_info_header interface_info;
+    struct usbredirfilter_rule *filter_rules;
+    int filter_rules_count;
 };
 
 struct AsyncURB {
@@ -780,6 +787,7 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
 static void usbredir_open_close_bh(void *opaque)
 {
     USBRedirDevice *dev = opaque;
+    uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
 
     usbredir_device_disconnect(dev);
 
@@ -810,7 +818,9 @@ static void usbredir_open_close_bh(void *opaque)
         dev->parser->interrupt_packet_func = usbredir_interrupt_packet;
         dev->read_buf = NULL;
         dev->read_buf_size = 0;
-        usbredirparser_init(dev->parser, VERSION, NULL, 0, 0);
+
+        usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
+        usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0);
         usbredirparser_do_write(dev->parser);
     }
 }
@@ -880,6 +890,17 @@ static int usbredir_initfn(USBDevice *udev)
         return -1;
     }
 
+    if (dev->filter_str) {
+        i = usbredirfilter_string_to_rules(dev->filter_str, ":", "|",
+                                           &dev->filter_rules,
+                                           &dev->filter_rules_count);
+        if (i) {
+            qerror_report(QERR_INVALID_PARAMETER_VALUE, "filter",
+                          "a usb device filter string");
+            return -1;
+        }
+    }
+
     dev->open_close_bh = qemu_bh_new(usbredir_open_close_bh, dev);
     dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev);
 
@@ -929,6 +950,44 @@ static void usbredir_handle_destroy(USBDevice *udev)
     if (dev->parser) {
         usbredirparser_destroy(dev->parser);
     }
+
+    free(dev->filter_rules);
+}
+
+static int usbredir_check_filter(USBRedirDevice *dev)
+{
+    if (dev->interface_info.interface_count == 0) {
+        ERROR("No interface info for device\n");
+        return -1;
+    }
+
+    if (dev->filter_rules) {
+        if (!usbredirparser_peer_has_cap(dev->parser,
+                                    usb_redir_cap_connect_device_version)) {
+            ERROR("Device filter specified and peer does not have the "
+                  "connect_device_version capability\n");
+            return -1;
+        }
+
+        if (usbredirfilter_check(
+                dev->filter_rules,
+                dev->filter_rules_count,
+                dev->device_info.device_class,
+                dev->device_info.device_subclass,
+                dev->device_info.device_protocol,
+                dev->interface_info.interface_class,
+                dev->interface_info.interface_subclass,
+                dev->interface_info.interface_protocol,
+                dev->interface_info.interface_count,
+                dev->device_info.vendor_id,
+                dev->device_info.product_id,
+                dev->device_info.device_version_bcd,
+                0) != 0) {
+            return -1;
+        }
+    }
+
+    return 0;
 }
 
 /*
@@ -957,6 +1016,7 @@ static void usbredir_device_connect(void *priv,
     struct usb_redir_device_connect_header *device_connect)
 {
     USBRedirDevice *dev = priv;
+    const char *speed;
 
     if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) {
         ERROR("Received device connect while already connected\n");
@@ -965,26 +1025,48 @@ static void usbredir_device_connect(void *priv,
 
     switch (device_connect->speed) {
     case usb_redir_speed_low:
-        DPRINTF("attaching low speed device\n");
+        speed = "low speed";
         dev->dev.speed = USB_SPEED_LOW;
         break;
     case usb_redir_speed_full:
-        DPRINTF("attaching full speed device\n");
+        speed = "full speed";
         dev->dev.speed = USB_SPEED_FULL;
         break;
     case usb_redir_speed_high:
-        DPRINTF("attaching high speed device\n");
+        speed = "high speed";
         dev->dev.speed = USB_SPEED_HIGH;
         break;
     case usb_redir_speed_super:
-        DPRINTF("attaching super speed device\n");
+        speed = "super speed";
         dev->dev.speed = USB_SPEED_SUPER;
         break;
     default:
-        DPRINTF("attaching unknown speed device, assuming full speed\n");
+        speed = "unknown speed";
         dev->dev.speed = USB_SPEED_FULL;
     }
+
+    if (usbredirparser_peer_has_cap(dev->parser,
+                                    usb_redir_cap_connect_device_version)) {
+        INFO("attaching %s device %04x:%04x version %d.%d class %02x\n",
+             speed, device_connect->vendor_id, device_connect->product_id,
+             device_connect->device_version_bcd >> 8,
+             device_connect->device_version_bcd & 0xff,
+             device_connect->device_class);
+    } else {
+        INFO("attaching %s device %04x:%04x class %02x\n", speed,
+             device_connect->vendor_id, device_connect->product_id,
+             device_connect->device_class);
+    }
+
     dev->dev.speedmask = (1 << dev->dev.speed);
+    dev->device_info = *device_connect;
+
+    if (usbredir_check_filter(dev)) {
+        WARNING("Device %04x:%04x rejected by device filter, not attaching\n",
+                device_connect->vendor_id, device_connect->product_id);
+        return;
+    }
+
     qemu_mod_timer(dev->attach_timer, dev->next_attach_time);
 }
 
@@ -1011,15 +1093,27 @@ static void usbredir_device_disconnect(void *priv)
     for (i = 0; i < MAX_ENDPOINTS; i++) {
         QTAILQ_INIT(&dev->endpoint[i].bufpq);
     }
+    dev->interface_info.interface_count = 0;
 }
 
 static void usbredir_interface_info(void *priv,
     struct usb_redir_interface_info_header *interface_info)
 {
-    /* The intention is to allow specifying acceptable interface classes
-       for redirection on the cmdline and in the future verify this here,
-       and disconnect (or never connect) the device if a not accepted
-       interface class is detected */
+    USBRedirDevice *dev = priv;
+
+    dev->interface_info = *interface_info;
+
+    /*
+     * If we receive interface info after the device has already been
+     * connected (ie on a set_config), re-check the filter.
+     */
+    if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) {
+        if (usbredir_check_filter(dev)) {
+            ERROR("Device no longer matches filter after interface info "
+                  "change, disconnecting!\n");
+            usbredir_device_disconnect(dev);
+        }
+    }
 }
 
 static void usbredir_ep_info(void *priv,
@@ -1318,6 +1412,7 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id,
 static Property usbredir_properties[] = {
     DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
     DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
+    DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str),
     DEFINE_PROP_END_OF_LIST(),
 };
 
commit f76e1d814241794467366d70d3d77849a6fd5ab0
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Fri Jan 13 14:28:56 2012 +0100

    usb-ehci: Clear the portstatus powner bit on device disconnect
    
    According to the EHCI spec port ownership should revert to the EHCI controller
    on device disconnect. This fixes the problem of a port getting stuck on USB 1
    when using redirection and plugging in a USB 2 device after a USB 1 device
    has been redirected.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 75ef71e..cdd7415 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -765,6 +765,11 @@ static void ehci_detach(USBPort *port)
         USBPort *companion = s->companion_ports[port->index];
         companion->ops->detach(companion);
         companion->dev = NULL;
+        /*
+         * EHCI spec 4.2.2: "When a disconnect occurs... On the event,
+         * the port ownership is returned immediately to the EHCI controller."
+         */
+        *portsc &= ~PORTSC_POWNER;
         return;
     }
 
commit 3200d1085df5f368885428e33d9439f55c7f1a47
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Jan 26 13:57:40 2012 +0100

    usb-uhci: implement bandwidth management
    
    The OS is allowed to make the UHCI Controller run in circles.  That is
    usually done to serve multiple connected USB devices in a robin-round
    fashion, so the available USB bandwidth is evenly distributed between
    devices.
    
    The uhci emulation handles this in a very poor way though.  When it
    figures it runs in circles it stops processing unconditionally, so
    it usually processes at most a single transfer desriptor per queue,
    even if there are multiple transfer descriptors are queued up.
    
    This patch makes uhci act in a more sophisticated way.  It keeps track
    of successful processed transfer descriptors and transfered bytes.  Then
    it will stop processing when there is nothing to do (no transfer
    descriptor was completed the last round) or when the transfered data
    reaches the usb bandwidth limit.
    
    Result is that the usb-storage devices connected to uhci are ten times
    faster, mkfs.vfat time for a 64M stick goes down from five seconds to
    a half second.  Reason for this is that we are now processing up to 20
    transfer descriptors (with 64 bytes each) per frame instead of a single
    one.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index cddcc89..e0c7dbb 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -73,7 +73,7 @@
 
 #define FRAME_TIMER_FREQ 1000
 
-#define FRAME_MAX_LOOPS  100
+#define FRAME_MAX_LOOPS  256
 
 #define NB_PORTS 2
 
@@ -942,7 +942,7 @@ static int qhdb_insert(QhDb *db, uint32_t addr)
 static void uhci_process_frame(UHCIState *s)
 {
     uint32_t frame_addr, link, old_td_ctrl, val, int_mask;
-    uint32_t curr_qh;
+    uint32_t curr_qh, td_count = 0, bytes_count = 0;
     int cnt, ret;
     UHCI_TD td;
     UHCI_QH qh;
@@ -967,13 +967,26 @@ static void uhci_process_frame(UHCIState *s)
             if (qhdb_insert(&qhdb, link)) {
                 /*
                  * We're going in circles. Which is not a bug because
-                 * HCD is allowed to do that as part of the BW management. 
-                 * In our case though it makes no sense to spin here. Sync transations 
-                 * are already done, and async completion handler will re-process 
-                 * the frame when something is ready.
+                 * HCD is allowed to do that as part of the BW management.
+                 *
+                 * Stop processing here if
+                 *  (a) no transaction has been done since we've been
+                 *      here last time, or
+                 *  (b) we've reached the usb 1.1 bandwidth, which is
+                 *      1280 bytes/frame.
                  */
                 DPRINTF("uhci: detected loop. qh 0x%x\n", link);
-                break;
+                if (td_count == 0) {
+                    DPRINTF("uhci: no transaction last round, stop\n");
+                    break;
+                } else if (bytes_count >= 1280) {
+                    DPRINTF("uhci: bandwidth limit reached, stop\n");
+                    break;
+                } else {
+                    td_count = 0;
+                    qhdb_reset(&qhdb);
+                    qhdb_insert(&qhdb, link);
+                }
             }
 
             pci_dma_read(&s->dev, link & ~0xf, &qh, sizeof(qh));
@@ -1033,6 +1046,8 @@ static void uhci_process_frame(UHCIState *s)
                 link, td.link, td.ctrl, td.token, curr_qh);
 
         link = td.link;
+        td_count++;
+        bytes_count += (td.ctrl & 0x7ff) + 1;
 
         if (curr_qh) {
 	    /* update QH element link */
commit 7bc9318bfb68b2d773449a55d4fa800d0fdb0918
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Feb 8 13:18:37 2012 +0100

    vnc: lift modifier keys on client disconnect.
    
    For any modifier key (shift, ctrl, alt) still pressed on disconnect
    inject a key-up event into the guest.  The vnc client is gone, it will
    not do that, so qemu has to do it instead.
    
    Without this keys will get stuck, making the guest act in weird ways
    after reconnecting.  Reproducer: exit vnc client via Alt-F4, guest
    continues to see the pressed alt key and will not react to key events
    in any useful way until you tap the alt key once to unstuck it.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/ui/vnc.c b/ui/vnc.c
index 83a9b15..02b71bc 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -46,6 +46,7 @@ static VncDisplay *vnc_display; /* needed for info vnc */
 static DisplayChangeListener *dcl;
 
 static int vnc_cursor_define(VncState *vs);
+static void vnc_release_modifiers(VncState *vs);
 
 static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
 {
@@ -1051,6 +1052,7 @@ static void vnc_disconnect_finish(VncState *vs)
     vnc_sasl_client_cleanup(vs);
 #endif /* CONFIG_VNC_SASL */
     audio_del(vs);
+    vnc_release_modifiers(vs);
 
     QTAILQ_REMOVE(&vs->vd->clients, vs, next);
 
@@ -1679,6 +1681,29 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
     }
 }
 
+static void vnc_release_modifiers(VncState *vs)
+{
+    static const int keycodes[] = {
+        /* shift, control, alt keys, both left & right */
+        0x2a, 0x36, 0x1d, 0x9d, 0x38, 0xb8,
+    };
+    int i, keycode;
+
+    if (!is_graphic_console()) {
+        return;
+    }
+    for (i = 0; i < ARRAY_SIZE(keycodes); i++) {
+        keycode = keycodes[i];
+        if (!vs->modifiers_state[keycode]) {
+            continue;
+        }
+        if (keycode & SCANCODE_GREY) {
+            kbd_put_keycode(SCANCODE_EMUL0);
+        }
+        kbd_put_keycode(keycode | SCANCODE_UP);
+    }
+}
+
 static void key_event(VncState *vs, int down, uint32_t sym)
 {
     int keycode;
commit 8cf364898cfe4ae761f2253e91a040633d6f87be
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Nov 24 18:10:49 2011 +0100

    vnc: implement shared flag handling.
    
    VNC clients send a shared flag in the client init message.  Up to now
    qemu completely ignores this.  This patch implements shared flag
    handling.  It comes with three policies:  By default qemu behaves as one
    would expect:  Asking for a exclusive access grants exclusive access to
    the client connecting.  There is also a desktop sharing mode which
    disallows exclusive connects (so one forgetting -shared wouldn't drop
    everybody else) and a compatibility mode which mimics the traditional
    (but non-conforming) qemu behavior.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/qemu-options.hx b/qemu-options.hx
index f577cc8..4bb3617 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1095,6 +1095,19 @@ This can be really helpful to save bandwidth when playing videos. Disabling
 adaptive encodings allows to restore the original static behavior of encodings
 like Tight.
 
+ at item share=[allow-exclusive|force-shared|ignore]
+
+Set display sharing policy.  'allow-exclusive' allows clients to ask
+for exclusive access.  As suggested by the rfb spec this is
+implemented by dropping other connections.  Connecting multiple
+clients in parallel requires all clients asking for a shared session
+(vncviewer: -shared switch).  This is the default.  'force-shared'
+disables exclusive client access.  Useful for shared desktop sessions,
+where you don't want someone forgetting specify -shared disconnect
+everybody else.  'ignore' completely ignores the shared flag and
+allows everybody connect unconditionally.  Doesn't conform to the rfb
+spec but is traditional qemu behavior.
+
 @end table
 ETEXI
 
diff --git a/ui/vnc.c b/ui/vnc.c
index 810582b..83a9b15 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -47,6 +47,29 @@ static DisplayChangeListener *dcl;
 
 static int vnc_cursor_define(VncState *vs);
 
+static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
+{
+#ifdef _VNC_DEBUG
+    static const char *mn[] = {
+        [0]                           = "undefined",
+        [VNC_SHARE_MODE_CONNECTING]   = "connecting",
+        [VNC_SHARE_MODE_SHARED]       = "shared",
+        [VNC_SHARE_MODE_EXCLUSIVE]    = "exclusive",
+        [VNC_SHARE_MODE_DISCONNECTED] = "disconnected",
+    };
+    fprintf(stderr, "%s/%d: %s -> %s\n", __func__,
+            vs->csock, mn[vs->share_mode], mn[mode]);
+#endif
+
+    if (vs->share_mode == VNC_SHARE_MODE_EXCLUSIVE) {
+        vs->vd->num_exclusive--;
+    }
+    vs->share_mode = mode;
+    if (vs->share_mode == VNC_SHARE_MODE_EXCLUSIVE) {
+        vs->vd->num_exclusive++;
+    }
+}
+
 static char *addr_to_string(const char *format,
                             struct sockaddr_storage *sa,
                             socklen_t salen) {
@@ -997,6 +1020,7 @@ static void vnc_disconnect_start(VncState *vs)
 {
     if (vs->csock == -1)
         return;
+    vnc_set_share_mode(vs, VNC_SHARE_MODE_DISCONNECTED);
     qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
     closesocket(vs->csock);
     vs->csock = -1;
@@ -2054,8 +2078,67 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
 static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
 {
     char buf[1024];
+    VncShareMode mode;
     int size;
 
+    mode = data[0] ? VNC_SHARE_MODE_SHARED : VNC_SHARE_MODE_EXCLUSIVE;
+    switch (vs->vd->share_policy) {
+    case VNC_SHARE_POLICY_IGNORE:
+        /*
+         * Ignore the shared flag.  Nothing to do here.
+         *
+         * Doesn't conform to the rfb spec but is traditional qemu
+         * behavior, thus left here as option for compatibility
+         * reasons.
+         */
+        break;
+    case VNC_SHARE_POLICY_ALLOW_EXCLUSIVE:
+        /*
+         * Policy: Allow clients ask for exclusive access.
+         *
+         * Implementation: When a client asks for exclusive access,
+         * disconnect all others. Shared connects are allowed as long
+         * as no exclusive connection exists.
+         *
+         * This is how the rfb spec suggests to handle the shared flag.
+         */
+        if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
+            VncState *client;
+            QTAILQ_FOREACH(client, &vs->vd->clients, next) {
+                if (vs == client) {
+                    continue;
+                }
+                if (client->share_mode != VNC_SHARE_MODE_EXCLUSIVE &&
+                    client->share_mode != VNC_SHARE_MODE_SHARED) {
+                    continue;
+                }
+                vnc_disconnect_start(client);
+            }
+        }
+        if (mode == VNC_SHARE_MODE_SHARED) {
+            if (vs->vd->num_exclusive > 0) {
+                vnc_disconnect_start(vs);
+                return 0;
+            }
+        }
+        break;
+    case VNC_SHARE_POLICY_FORCE_SHARED:
+        /*
+         * Policy: Shared connects only.
+         * Implementation: Disallow clients asking for exclusive access.
+         *
+         * Useful for shared desktop sessions where you don't want
+         * someone forgetting to say -shared when running the vnc
+         * client disconnect everybody else.
+         */
+        if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
+            vnc_disconnect_start(vs);
+            return 0;
+        }
+        break;
+    }
+    vnc_set_share_mode(vs, mode);
+
     vs->client_width = ds_get_width(vs->ds);
     vs->client_height = ds_get_height(vs->ds);
     vnc_write_u16(vs, vs->client_width);
@@ -2562,6 +2645,7 @@ static void vnc_connect(VncDisplay *vd, int csock, int skipauth)
 
     vnc_client_cache_addr(vs);
     vnc_qmp_event(vs, QEVENT_VNC_CONNECTED);
+    vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING);
 
     vs->vd = vd;
     vs->ds = vd->ds;
@@ -2755,6 +2839,7 @@ int vnc_display_open(DisplayState *ds, const char *display)
 
     if (!(vs->display = strdup(display)))
         return -1;
+    vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
 
     options = display;
     while ((options = strchr(options, ','))) {
@@ -2810,6 +2895,19 @@ int vnc_display_open(DisplayState *ds, const char *display)
             vs->lossy = true;
         } else if (strncmp(options, "non-adapative", 13) == 0) {
             vs->non_adaptive = true;
+        } else if (strncmp(options, "share=", 6) == 0) {
+            if (strncmp(options+6, "ignore", 6) == 0) {
+                vs->share_policy = VNC_SHARE_POLICY_IGNORE;
+            } else if (strncmp(options+6, "allow-exclusive", 15) == 0) {
+                vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
+            } else if (strncmp(options+6, "force-shared", 12) == 0) {
+                vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
+            } else {
+                fprintf(stderr, "unknown vnc share= option\n");
+                g_free(vs->display);
+                vs->display = NULL;
+                return -1;
+            }
         }
     }
 
diff --git a/ui/vnc.h b/ui/vnc.h
index 66689f1..0bd1fc6 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -122,9 +122,24 @@ struct VncSurface
     DisplaySurface *ds;
 };
 
+typedef enum VncShareMode {
+    VNC_SHARE_MODE_CONNECTING = 1,
+    VNC_SHARE_MODE_SHARED,
+    VNC_SHARE_MODE_EXCLUSIVE,
+    VNC_SHARE_MODE_DISCONNECTED,
+} VncShareMode;
+
+typedef enum VncSharePolicy {
+    VNC_SHARE_POLICY_IGNORE = 1,
+    VNC_SHARE_POLICY_ALLOW_EXCLUSIVE,
+    VNC_SHARE_POLICY_FORCE_SHARED,
+} VncSharePolicy;
+
 struct VncDisplay
 {
     QTAILQ_HEAD(, VncState) clients;
+    int num_exclusive;
+    VncSharePolicy share_policy;
     QEMUTimer *timer;
     int timer_interval;
     int lsock;
@@ -250,6 +265,7 @@ struct VncState
     int last_y;
     int client_width;
     int client_height;
+    VncShareMode share_mode;
 
     uint32_t vnc_encoding;
 
commit e26437c2d4a7f6cbbc0bbd51b08a2dcce84bb93b
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Nov 8 10:02:16 2011 +0100

    vnc: fix ctrl key in vnc terminal emulation
    
    Make the control keys for terminals on the vnc display
    (i.e. qemu -vnc :0 -serial vc) work.  Makes the terminals
    alot more usable as typing Ctrl-C in your serial console
    actually has the desired effect ;)
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/ui/vnc.c b/ui/vnc.c
index 5752bf8..810582b 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1552,9 +1552,11 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
         else
             kbd_put_keycode(keycode | SCANCODE_UP);
     } else {
+        bool numlock = vs->modifiers_state[0x45];
+        bool control = (vs->modifiers_state[0x1d] ||
+                        vs->modifiers_state[0x9d]);
         /* QEMU console emulation */
         if (down) {
-            int numlock = vs->modifiers_state[0x45];
             switch (keycode) {
             case 0x2a:                          /* Left Shift */
             case 0x36:                          /* Right Shift */
@@ -1642,7 +1644,11 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
                 break;
 
             default:
-                kbd_put_keysym(sym);
+                if (control) {
+                    kbd_put_keysym(sym & 0x1f);
+                } else {
+                    kbd_put_keysym(sym);
+                }
                 break;
             }
         }
commit ce3e14175ea36d851aede808fc8891313b91ec27
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Mon Jun 14 12:28:23 2010 +0200

    Fix vnc memory corruption with width = 1400
    
    vnc assumes that the screen width is a multiple of 16 in several places.
    If this is not the case vnc will overrun buffers, corrupt memory, make
    qemu crash.
    
    This is the minimum fix for this bug. It makes sure we don't overrun the
    scanline, thereby fixing the segfault.  The rendering is *not* correct
    though, there is a black border at the right side of the screen, 8
    pixels wide because 1400 % 16 == 8.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/ui/vnc.c b/ui/vnc.c
index 16b79ec..5752bf8 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2445,7 +2445,7 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
             guest_ptr  = guest_row;
             server_ptr = server_row;
 
-            for (x = 0; x < vd->guest.ds->width;
+            for (x = 0; x + 15 < vd->guest.ds->width;
                     x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
                 if (!test_and_clear_bit((x / 16), vd->guest.dirty[y]))
                     continue;
commit 57c83dacfe179bf061b8fa79d9553ebabe4d2ff4
Author: Stefan Weil <sw at weilnetz.de>
Date:   Wed Feb 8 22:41:37 2012 +0100

    make: Remove duplicate use of GLIB_CFLAGS
    
    Makefile, Makefile.hw, Makefile.target and libcacard/Makefile
    added GLIB_CFLAGS to QEMU_CFLAGS.
    
    Makefile.objs does this, too, and is included by all other
    Makefiles, so GLIB_CFLAGS were added twice (reported by malc).
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/Makefile b/Makefile
index 47acf3d..e66e885 100644
--- a/Makefile
+++ b/Makefile
@@ -114,8 +114,6 @@ audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
 
 QEMU_CFLAGS+=$(CURL_CFLAGS)
 
-QEMU_CFLAGS+=$(GLIB_CFLAGS)
-
 QEMU_CFLAGS += -I$(SRC_PATH)/include
 
 ui/cocoa.o: ui/cocoa.m
diff --git a/Makefile.hw b/Makefile.hw
index 7b8d068..33f1ab0 100644
--- a/Makefile.hw
+++ b/Makefile.hw
@@ -10,7 +10,6 @@ include $(SRC_PATH)/rules.mak
 $(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw)
 
 QEMU_CFLAGS+=-I..
-QEMU_CFLAGS += $(GLIB_CFLAGS)
 QEMU_CFLAGS += -I$(SRC_PATH)/include
 
 include $(SRC_PATH)/Makefile.objs
diff --git a/Makefile.objs b/Makefile.objs
index ec35320..391e524 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -323,8 +323,6 @@ hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
 9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-proxy.o
 
 hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
-$(addprefix 9pfs/, $(9pfs-nested-y)): QEMU_CFLAGS+=$(GLIB_CFLAGS)
-
 
 ######################################################################
 # libdis
diff --git a/Makefile.target b/Makefile.target
index 7ed4979..29fde6e 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -215,7 +215,6 @@ QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
 QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
 QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
-QEMU_CFLAGS += $(GLIB_CFLAGS)
 
 # xen support
 obj-$(CONFIG_XEN) += xen-all.o xen_machine_pv.o xen_domainbuild.o xen-mapcache.o
diff --git a/libcacard/Makefile b/libcacard/Makefile
index a145569..c6a896a 100644
--- a/libcacard/Makefile
+++ b/libcacard/Makefile
@@ -15,8 +15,6 @@ QEMU_OBJS_LIB=$(addsuffix .lo,$(basename $(QEMU_OBJS)))
 
 QEMU_CFLAGS+=-I../
 
-QEMU_CFLAGS+=$(GLIB_CFLAGS)
-
 libcacard.lib-y=$(addsuffix .lo,$(basename $(libcacard-y)))
 
 vscclient: $(libcacard-y) $(QEMU_OBJS) vscclient.o
commit b867672884afc39b6537a8aa6aa2f20a5154bf4f
Author: Alexander Graf <agraf at suse.de>
Date:   Mon Jan 30 23:29:48 2012 +0100

    AHCI: Masking of IRQs actually masks them
    
    When masking IRQ lines, we should actually mask them out and not declare
    them active anymore. Once we mask them in again, they are allowed to trigger
    again.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index caff7bc..f7ef114 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -146,6 +146,7 @@ static void ahci_check_irq(AHCIState *s)
 
     DPRINTF(-1, "check irq %#x\n", s->control_regs.irqstatus);
 
+    s->control_regs.irqstatus = 0;
     for (i = 0; i < s->ports; i++) {
         AHCIPortRegs *pr = &s->dev[i].port_regs;
         if (pr->irq_stat & pr->irq_mask) {
@@ -216,6 +217,7 @@ static void  ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
             break;
         case PORT_IRQ_STAT:
             pr->irq_stat &= ~val;
+            ahci_check_irq(s);
             break;
         case PORT_IRQ_MASK:
             pr->irq_mask = val & 0xfdc000ff;
commit 6d1acda8f16d1f2d0b05cfbf9ce54d05849cb016
Author: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
Date:   Tue Jan 31 02:10:06 2012 +0900

    sheepdog: fix co_recv coroutine context
    
    The co_recv coroutine has two things that will try to enter it:
    
      1. The select(2) read callback on the sheepdog socket.
      2. The aio_add_request() blocking operations, including a coroutine
         mutex.
    
    This patch fixes it by setting NULL to co_recv before sending data.
    
    In future, we should make the sheepdog driver fully coroutine-based
    and simplify request handling.
    
    Signed-off-by: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/sheepdog.c b/block/sheepdog.c
index 9416400..00276f6 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -629,6 +629,9 @@ static void coroutine_fn aio_read_response(void *opaque)
 
     switch (acb->aiocb_type) {
     case AIOCB_WRITE_UDATA:
+        /* this coroutine context is no longer suitable for co_recv
+         * because we may send data to update vdi objects */
+        s->co_recv = NULL;
         if (!is_data_obj(aio_req->oid)) {
             break;
         }
commit c9b308d20b642c106048f088ccc31f2aa7cf59ba
Author: Alexander Graf <agraf at suse.de>
Date:   Mon Jan 30 23:29:47 2012 +0100

    AHCI: Fix port reset race
    
    bdrv_aio_cancel() can trigger bdrv_aio_flush() which makes all aio
    that is currently in flight finish. So what we do is:
    
      port reset
      detect ncq in flight
      cancel ncq
      delete ncq sg list
    
    at which point we have double freed the sg list. Instead, with this
    patch we do:
    
      port reset
      detect ncq in flight
      cancel ncq
      check if we are really still in flight
      delete ncq sg list
    
    which makes things work and gets rid of the race.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index c87a6ca..caff7bc 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -560,6 +560,11 @@ static void ahci_reset_port(AHCIState *s, int port)
             ncq_tfs->aiocb = NULL;
         }
 
+        /* Maybe we just finished the request thanks to bdrv_aio_cancel() */
+        if (!ncq_tfs->used) {
+            continue;
+        }
+
         qemu_sglist_destroy(&ncq_tfs->sglist);
         ncq_tfs->used = 0;
     }
commit ea8f978ffef325ab2fd0edcf5f24b6dcec6078f3
Author: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>
Date:   Tue Dec 20 17:03:47 2011 +0800

    rewrite QEMU_BUILD_BUG_ON
    
    On some platforms, __LINE__ will not expand to real number in QEMU_BUILD_BUG_ON,
    so if using QEMU_BUILD_BUG_ON twice, compiler will report errors. This patch will
    fix it.
    
    BTW, I got error message on RHEL 6.1/gcc 4.4.5.
    
    Signed-off-by: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/compiler.h b/compiler.h
index a1c0794..736e770 100644
--- a/compiler.h
+++ b/compiler.h
@@ -30,8 +30,10 @@
 # define QEMU_PACKED __attribute__((packed))
 #endif
 
+#define cat(x,y) x ## y
+#define cat2(x,y) cat(x,y)
 #define QEMU_BUILD_BUG_ON(x) \
-    typedef char qemu_build_bug_on__##__LINE__[(x)?-1:1];
+    typedef char cat2(qemu_build_bug_on__,__LINE__)[(x)?-1:1];
 
 #if defined __GNUC__
 # if !QEMU_GNUC_PREREQ(4, 4)
commit 75bab85ca01876f912caf46f5fcb4ca8d9a50584
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Feb 2 14:52:08 2012 +0100

    qcow2: Keep unknown header extension when rewriting header
    
    If we want header extensions to work as compatible extensions, we can't
    destroy yet unknown header extensions when rewriting the header (e.g.
    for changing the backing file). Save all unknown header extensions in a
    list of blobs and include them in a new header.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2.c b/block/qcow2.c
index 9f8c2de..3692b45 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -77,8 +77,10 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
 static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
                                  uint64_t end_offset)
 {
+    BDRVQcowState *s = bs->opaque;
     QCowExtension ext;
     uint64_t offset;
+    int ret;
 
 #ifdef DEBUG_EXT
     printf("qcow2_read_extensions: start=%ld end=%ld\n", start_offset, end_offset);
@@ -129,8 +131,22 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
             break;
 
         default:
-            /* unknown magic -- just skip it */
-            offset = ((offset + ext.len + 7) & ~7);
+            /* unknown magic - save it in case we need to rewrite the header */
+            {
+                Qcow2UnknownHeaderExtension *uext;
+
+                uext = g_malloc0(sizeof(*uext)  + ext.len);
+                uext->magic = ext.magic;
+                uext->len = ext.len;
+                QLIST_INSERT_HEAD(&s->unknown_header_ext, uext, next);
+
+                ret = bdrv_pread(bs->file, offset , uext->data, uext->len);
+                if (ret < 0) {
+                    return ret;
+                }
+
+                offset = ((offset + ext.len + 7) & ~7);
+            }
             break;
         }
     }
@@ -138,6 +154,16 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
     return 0;
 }
 
+static void cleanup_unknown_header_ext(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    Qcow2UnknownHeaderExtension *uext, *next;
+
+    QLIST_FOREACH_SAFE(uext, &s->unknown_header_ext, next, next) {
+        QLIST_REMOVE(uext, next);
+        g_free(uext);
+    }
+}
 
 static int qcow2_open(BlockDriverState *bs, int flags)
 {
@@ -291,6 +317,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
     return ret;
 
  fail:
+    cleanup_unknown_header_ext(bs);
     qcow2_free_snapshots(bs);
     qcow2_refcount_close(bs);
     g_free(s->l1_table);
@@ -632,6 +659,7 @@ static void qcow2_close(BlockDriverState *bs)
     qcow2_cache_destroy(bs, s->l2_table_cache);
     qcow2_cache_destroy(bs, s->refcount_block_cache);
 
+    cleanup_unknown_header_ext(bs);
     g_free(s->cluster_cache);
     qemu_vfree(s->cluster_data);
     qcow2_refcount_close(bs);
@@ -705,6 +733,7 @@ int qcow2_update_header(BlockDriverState *bs)
     int ret;
     uint64_t total_size;
     uint32_t refcount_table_clusters;
+    Qcow2UnknownHeaderExtension *uext;
 
     buf = qemu_blockalign(bs, buflen);
     memset(buf, 0, s->cluster_size);
@@ -752,6 +781,17 @@ int qcow2_update_header(BlockDriverState *bs)
         buflen -= ret;
     }
 
+    /* Keep unknown header extensions */
+    QLIST_FOREACH(uext, &s->unknown_header_ext, next) {
+        ret = header_ext_add(buf, uext->magic, uext->data, uext->len, buflen);
+        if (ret < 0) {
+            goto fail;
+        }
+
+        buf += ret;
+        buflen -= ret;
+    }
+
     /* End of header extensions */
     ret = header_ext_add(buf, QCOW2_EXT_MAGIC_END, NULL, 0, buflen);
     if (ret < 0) {
diff --git a/block/qcow2.h b/block/qcow2.h
index aae5f89..fc35838 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -87,6 +87,13 @@ typedef struct QCowSnapshot {
 struct Qcow2Cache;
 typedef struct Qcow2Cache Qcow2Cache;
 
+typedef struct Qcow2UnknownHeaderExtension {
+    uint32_t magic;
+    uint32_t len;
+    QLIST_ENTRY(Qcow2UnknownHeaderExtension) next;
+    uint8_t data[];
+} Qcow2UnknownHeaderExtension;
+
 typedef struct BDRVQcowState {
     int cluster_bits;
     int cluster_size;
@@ -127,6 +134,7 @@ typedef struct BDRVQcowState {
     QCowSnapshot *snapshots;
 
     int flags;
+    QLIST_HEAD(, Qcow2UnknownHeaderExtension) unknown_header_ext;
 } BDRVQcowState;
 
 /* XXX: use std qcow open function ? */
commit e24e49e6194626e4ec9f1aecce6d6a6847320bce
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Feb 2 12:32:31 2012 +0100

    qcow2: Update whole header at once
    
    In order to switch the backing file, qcow2 issues multiple write
    requests that only changed a part of the image header. Any failure after
    the first one would leave the header in an corrupted state. With this
    patch, the whole header is written at once, so we can't fail in the
    middle.
    
    At the same time, this gives us a reusable functions that updates all
    fields of the qcow2 header and not only the backing file.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2.c b/block/qcow2.c
index aa32e8d..9f8c2de 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -669,103 +669,137 @@ static void qcow2_invalidate_cache(BlockDriverState *bs)
     }
 }
 
+static size_t header_ext_add(char *buf, uint32_t magic, const void *s,
+    size_t len, size_t buflen)
+{
+    QCowExtension *ext_backing_fmt = (QCowExtension*) buf;
+    size_t ext_len = sizeof(QCowExtension) + ((len + 7) & ~7);
+
+    if (buflen < ext_len) {
+        return -ENOSPC;
+    }
+
+    *ext_backing_fmt = (QCowExtension) {
+        .magic  = cpu_to_be32(magic),
+        .len    = cpu_to_be32(len),
+    };
+    memcpy(buf + sizeof(QCowExtension), s, len);
+
+    return ext_len;
+}
+
 /*
- * Updates the variable length parts of the qcow2 header, i.e. the backing file
- * name and all extensions. qcow2 was not designed to allow such changes, so if
- * we run out of space (we can only use the first cluster) this function may
- * fail.
+ * Updates the qcow2 header, including the variable length parts of it, i.e.
+ * the backing file name and all extensions. qcow2 was not designed to allow
+ * such changes, so if we run out of space (we can only use the first cluster)
+ * this function may fail.
  *
  * Returns 0 on success, -errno in error cases.
  */
-static int qcow2_update_ext_header(BlockDriverState *bs,
-    const char *backing_file, const char *backing_fmt)
+int qcow2_update_header(BlockDriverState *bs)
 {
-    size_t backing_file_len = 0;
-    size_t backing_fmt_len = 0;
     BDRVQcowState *s = bs->opaque;
-    QCowExtension ext_backing_fmt = {0, 0};
+    QCowHeader *header;
+    char *buf;
+    size_t buflen = s->cluster_size;
     int ret;
+    uint64_t total_size;
+    uint32_t refcount_table_clusters;
 
-    /* Backing file format doesn't make sense without a backing file */
-    if (backing_fmt && !backing_file) {
-        return -EINVAL;
-    }
-
-    /* Prepare the backing file format extension if needed */
-    if (backing_fmt) {
-        ext_backing_fmt.len = cpu_to_be32(strlen(backing_fmt));
-        ext_backing_fmt.magic = cpu_to_be32(QCOW2_EXT_MAGIC_BACKING_FORMAT);
-        backing_fmt_len = ((sizeof(ext_backing_fmt)
-            + strlen(backing_fmt) + 7) & ~7);
-    }
+    buf = qemu_blockalign(bs, buflen);
+    memset(buf, 0, s->cluster_size);
 
-    /* Check if we can fit the new header into the first cluster */
-    if (backing_file) {
-        backing_file_len = strlen(backing_file);
-    }
+    /* Header structure */
+    header = (QCowHeader*) buf;
 
-    size_t header_size = sizeof(QCowHeader) + backing_file_len
-        + backing_fmt_len;
-
-    if (header_size > s->cluster_size) {
-        return -ENOSPC;
+    if (buflen < sizeof(*header)) {
+        ret = -ENOSPC;
+        goto fail;
     }
 
-    /* Rewrite backing file name and qcow2 extensions */
-    size_t ext_size = header_size - sizeof(QCowHeader);
-    uint8_t buf[ext_size];
-    size_t offset = 0;
-    size_t backing_file_offset = 0;
-
-    if (backing_file) {
-        if (backing_fmt) {
-            int padding = backing_fmt_len -
-                (sizeof(ext_backing_fmt) + strlen(backing_fmt));
-
-            memcpy(buf + offset, &ext_backing_fmt, sizeof(ext_backing_fmt));
-            offset += sizeof(ext_backing_fmt);
+    total_size = bs->total_sectors * BDRV_SECTOR_SIZE;
+    refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
+
+    *header = (QCowHeader) {
+        .magic                  = cpu_to_be32(QCOW_MAGIC),
+        .version                = cpu_to_be32(QCOW_VERSION),
+        .backing_file_offset    = 0,
+        .backing_file_size      = 0,
+        .cluster_bits           = cpu_to_be32(s->cluster_bits),
+        .size                   = cpu_to_be64(total_size),
+        .crypt_method           = cpu_to_be32(s->crypt_method_header),
+        .l1_size                = cpu_to_be32(s->l1_size),
+        .l1_table_offset        = cpu_to_be64(s->l1_table_offset),
+        .refcount_table_offset  = cpu_to_be64(s->refcount_table_offset),
+        .refcount_table_clusters = cpu_to_be32(refcount_table_clusters),
+        .nb_snapshots           = cpu_to_be32(s->nb_snapshots),
+        .snapshots_offset       = cpu_to_be64(s->snapshots_offset),
+    };
 
-            memcpy(buf + offset, backing_fmt, strlen(backing_fmt));
-            offset += strlen(backing_fmt);
+    buf += sizeof(*header);
+    buflen -= sizeof(*header);
 
-            memset(buf + offset, 0, padding);
-            offset += padding;
+    /* Backing file format header extension */
+    if (*bs->backing_format) {
+        ret = header_ext_add(buf, QCOW2_EXT_MAGIC_BACKING_FORMAT,
+                             bs->backing_format, strlen(bs->backing_format),
+                             buflen);
+        if (ret < 0) {
+            goto fail;
         }
 
-        memcpy(buf + offset, backing_file, backing_file_len);
-        backing_file_offset = sizeof(QCowHeader) + offset;
+        buf += ret;
+        buflen -= ret;
     }
 
-    ret = bdrv_pwrite_sync(bs->file, sizeof(QCowHeader), buf, ext_size);
+    /* End of header extensions */
+    ret = header_ext_add(buf, QCOW2_EXT_MAGIC_END, NULL, 0, buflen);
     if (ret < 0) {
         goto fail;
     }
 
-    /* Update header fields */
-    uint64_t be_backing_file_offset = cpu_to_be64(backing_file_offset);
-    uint32_t be_backing_file_size = cpu_to_be32(backing_file_len);
+    buf += ret;
+    buflen -= ret;
 
-    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, backing_file_offset),
-        &be_backing_file_offset, sizeof(uint64_t));
-    if (ret < 0) {
-        goto fail;
+    /* Backing file name */
+    if (*bs->backing_file) {
+        size_t backing_file_len = strlen(bs->backing_file);
+
+        if (buflen < backing_file_len) {
+            ret = -ENOSPC;
+            goto fail;
+        }
+
+        strncpy(buf, bs->backing_file, buflen);
+
+        header->backing_file_offset = cpu_to_be64(buf - ((char*) header));
+        header->backing_file_size   = cpu_to_be32(backing_file_len);
     }
 
-    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, backing_file_size),
-        &be_backing_file_size, sizeof(uint32_t));
+    /* Write the new header */
+    ret = bdrv_pwrite(bs->file, 0, header, s->cluster_size);
     if (ret < 0) {
         goto fail;
     }
 
     ret = 0;
 fail:
+    qemu_vfree(header);
     return ret;
 }
 
 static int qcow2_change_backing_file(BlockDriverState *bs,
     const char *backing_file, const char *backing_fmt)
 {
-    return qcow2_update_ext_header(bs, backing_file, backing_fmt);
+    /* Backing file format doesn't make sense without a backing file */
+    if (backing_fmt && !backing_file) {
+        return -EINVAL;
+    }
+
+    pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: "");
+    pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: "");
+
+    return qcow2_update_header(bs);
 }
 
 static int preallocate(BlockDriverState *bs)
diff --git a/block/qcow2.h b/block/qcow2.h
index 99e4536..aae5f89 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -178,6 +178,7 @@ static inline int64_t align_offset(int64_t offset, int n)
 /* qcow2.c functions */
 int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
                   int64_t sector_num, int nb_sectors);
+int qcow2_update_header(BlockDriverState *bs);
 
 /* qcow2-refcount.c functions */
 int qcow2_refcount_init(BlockDriverState *bs);
commit ecd880d9eeb59a0148d4761698448245ec4306e0
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Tue Feb 7 10:15:47 2012 +0100

    vpc: Round up image size during fixed image creation
    
    The geometry calculation algorithm from the VHD spec rounds the image
    size down if it doesn't exactly match a geometry. During image
    conversion, this causes the image to be truncated. For dynamic images,
    we already have code in place to round up instead, let's do the same for
    fixed images.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vpc.c b/block/vpc.c
index db6b14b..6b4816f 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -685,24 +685,21 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
         return -EIO;
     }
 
+    /*
+     * Calculate matching total_size and geometry. Increase the number of
+     * sectors requested until we get enough (or fail). This ensures that
+     * qemu-img convert doesn't truncate images, but rather rounds up.
+     */
     total_sectors = total_size / BDRV_SECTOR_SIZE;
-    if (disk_type == VHD_DYNAMIC) {
-        /* Calculate matching total_size and geometry. Increase the number of
-           sectors requested until we get enough (or fail). */
-        for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl;
-             i++) {
-            if (calculate_geometry(total_sectors + i,
-                                   &cyls, &heads, &secs_per_cyl)) {
-                ret = -EFBIG;
-                goto fail;
-            }
-        }
-    } else {
-        if (calculate_geometry(total_sectors, &cyls, &heads, &secs_per_cyl)) {
+    for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
+        if (calculate_geometry(total_sectors + i, &cyls, &heads,
+                               &secs_per_cyl))
+        {
             ret = -EFBIG;
             goto fail;
         }
     }
+
     total_sectors = (int64_t) cyls * heads * secs_per_cyl;
 
     /* Prepare the Hard Disk Footer */
commit 24da78dbb54b61fa299919c89709270fad5e682d
Author: Charles Arnold <carnold at suse.com>
Date:   Mon Feb 6 09:22:30 2012 -0700

    vpc: Add support for Fixed Disk type
    
    The Virtual Hard Disk Image Format Specification allows for three
    types of hard disk formats, Fixed, Dynamic, and Differencing.  Qemu
    currently only supports Dynamic disks.  This patch adds support for
    the Fixed Disk format.
    
    Usage:
        Example 1: qemu-img create -f vpc -o type=fixed <filename> [size]
        Example 2: qemu-img convert -O vpc -o type=fixed <input filename> <output filename>
    
    While it is also allowed to specify '-o type=dynamic', the default disk type
    remains Dynamic and is what is used when the type is left unspecified.
    
    Signed-off-by: Charles Arnold <carnold at suse.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vpc.c b/block/vpc.c
index 89a5ee2..db6b14b 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -161,13 +161,27 @@ static int vpc_open(BlockDriverState *bs, int flags)
     uint8_t buf[HEADER_SIZE];
     uint32_t checksum;
     int err = -1;
+    int disk_type = VHD_DYNAMIC;
 
     if (bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
         goto fail;
 
     footer = (struct vhd_footer*) s->footer_buf;
-    if (strncmp(footer->creator, "conectix", 8))
-        goto fail;
+    if (strncmp(footer->creator, "conectix", 8)) {
+        int64_t offset = bdrv_getlength(bs->file);
+        if (offset < HEADER_SIZE) {
+            goto fail;
+        }
+        /* If a fixed disk, the footer is found only at the end of the file */
+        if (bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf, HEADER_SIZE)
+                != HEADER_SIZE) {
+            goto fail;
+        }
+        if (strncmp(footer->creator, "conectix", 8)) {
+            goto fail;
+        }
+        disk_type = VHD_FIXED;
+    }
 
     checksum = be32_to_cpu(footer->checksum);
     footer->checksum = 0;
@@ -186,49 +200,54 @@ static int vpc_open(BlockDriverState *bs, int flags)
         goto fail;
     }
 
-    if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE)
-            != HEADER_SIZE)
-        goto fail;
-
-    dyndisk_header = (struct vhd_dyndisk_header*) buf;
+    if (disk_type == VHD_DYNAMIC) {
+        if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf,
+                HEADER_SIZE) != HEADER_SIZE) {
+            goto fail;
+        }
 
-    if (strncmp(dyndisk_header->magic, "cxsparse", 8))
-        goto fail;
+        dyndisk_header = (struct vhd_dyndisk_header *) buf;
 
+        if (strncmp(dyndisk_header->magic, "cxsparse", 8)) {
+            goto fail;
+        }
 
-    s->block_size = be32_to_cpu(dyndisk_header->block_size);
-    s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
+        s->block_size = be32_to_cpu(dyndisk_header->block_size);
+        s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
 
-    s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
-    s->pagetable = g_malloc(s->max_table_entries * 4);
+        s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
+        s->pagetable = g_malloc(s->max_table_entries * 4);
 
-    s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
-    if (bdrv_pread(bs->file, s->bat_offset, s->pagetable,
-            s->max_table_entries * 4) != s->max_table_entries * 4)
-	    goto fail;
+        s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
+        if (bdrv_pread(bs->file, s->bat_offset, s->pagetable,
+                s->max_table_entries * 4) != s->max_table_entries * 4) {
+            goto fail;
+        }
 
-    s->free_data_block_offset =
-        (s->bat_offset + (s->max_table_entries * 4) + 511) & ~511;
+        s->free_data_block_offset =
+            (s->bat_offset + (s->max_table_entries * 4) + 511) & ~511;
 
-    for (i = 0; i < s->max_table_entries; i++) {
-        be32_to_cpus(&s->pagetable[i]);
-        if (s->pagetable[i] != 0xFFFFFFFF) {
-            int64_t next = (512 * (int64_t) s->pagetable[i]) +
-                s->bitmap_size + s->block_size;
+        for (i = 0; i < s->max_table_entries; i++) {
+            be32_to_cpus(&s->pagetable[i]);
+            if (s->pagetable[i] != 0xFFFFFFFF) {
+                int64_t next = (512 * (int64_t) s->pagetable[i]) +
+                    s->bitmap_size + s->block_size;
 
-            if (next> s->free_data_block_offset)
-                s->free_data_block_offset = next;
+                if (next > s->free_data_block_offset) {
+                    s->free_data_block_offset = next;
+                }
+            }
         }
-    }
 
-    s->last_bitmap_offset = (int64_t) -1;
+        s->last_bitmap_offset = (int64_t) -1;
 
 #ifdef CACHE
-    s->pageentry_u8 = g_malloc(512);
-    s->pageentry_u32 = s->pageentry_u8;
-    s->pageentry_u16 = s->pageentry_u8;
-    s->last_pagetable = -1;
+        s->pageentry_u8 = g_malloc(512);
+        s->pageentry_u32 = s->pageentry_u8;
+        s->pageentry_u16 = s->pageentry_u8;
+        s->last_pagetable = -1;
 #endif
+    }
 
     qemu_co_mutex_init(&s->lock);
 
@@ -395,7 +414,11 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num,
     int ret;
     int64_t offset;
     int64_t sectors, sectors_per_block;
+    struct vhd_footer *footer = (struct vhd_footer *) s->footer_buf;
 
+    if (cpu_to_be32(footer->type) == VHD_FIXED) {
+        return bdrv_read(bs->file, sector_num, buf, nb_sectors);
+    }
     while (nb_sectors > 0) {
         offset = get_sector_offset(bs, sector_num, 0);
 
@@ -440,7 +463,11 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num,
     int64_t offset;
     int64_t sectors, sectors_per_block;
     int ret;
+    struct vhd_footer *footer =  (struct vhd_footer *) s->footer_buf;
 
+    if (cpu_to_be32(footer->type) == VHD_FIXED) {
+        return bdrv_write(bs->file, sector_num, buf, nb_sectors);
+    }
     while (nb_sectors > 0) {
         offset = get_sector_offset(bs, sector_num, 1);
 
@@ -533,70 +560,14 @@ static int calculate_geometry(int64_t total_sectors, uint16_t* cyls,
     return 0;
 }
 
-static int vpc_create(const char *filename, QEMUOptionParameter *options)
+static int create_dynamic_disk(int fd, uint8_t *buf, int64_t total_sectors)
 {
-    uint8_t buf[1024];
-    struct vhd_footer* footer = (struct vhd_footer*) buf;
     struct vhd_dyndisk_header* dyndisk_header =
         (struct vhd_dyndisk_header*) buf;
-    int fd, i;
-    uint16_t cyls = 0;
-    uint8_t heads = 0;
-    uint8_t secs_per_cyl = 0;
     size_t block_size, num_bat_entries;
-    int64_t total_sectors = 0;
+    int i;
     int ret = -EIO;
 
-    // Read out options
-    total_sectors = get_option_parameter(options, BLOCK_OPT_SIZE)->value.n /
-                    BDRV_SECTOR_SIZE;
-
-    // Create the file
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
-    if (fd < 0)
-        return -EIO;
-
-    /* Calculate matching total_size and geometry. Increase the number of
-       sectors requested until we get enough (or fail). */
-    for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
-        if (calculate_geometry(total_sectors + i,
-                               &cyls, &heads, &secs_per_cyl)) {
-            ret = -EFBIG;
-            goto fail;
-        }
-    }
-    total_sectors = (int64_t) cyls * heads * secs_per_cyl;
-
-    // Prepare the Hard Disk Footer
-    memset(buf, 0, 1024);
-
-    memcpy(footer->creator, "conectix", 8);
-    // TODO Check if "qemu" creator_app is ok for VPC
-    memcpy(footer->creator_app, "qemu", 4);
-    memcpy(footer->creator_os, "Wi2k", 4);
-
-    footer->features = be32_to_cpu(0x02);
-    footer->version = be32_to_cpu(0x00010000);
-    footer->data_offset = be64_to_cpu(HEADER_SIZE);
-    footer->timestamp = be32_to_cpu(time(NULL) - VHD_TIMESTAMP_BASE);
-
-    // Version of Virtual PC 2007
-    footer->major = be16_to_cpu(0x0005);
-    footer->minor =be16_to_cpu(0x0003);
-
-    footer->orig_size = be64_to_cpu(total_sectors * 512);
-    footer->size = be64_to_cpu(total_sectors * 512);
-
-    footer->cyls = be16_to_cpu(cyls);
-    footer->heads = heads;
-    footer->secs_per_cyl = secs_per_cyl;
-
-    footer->type = be32_to_cpu(VHD_DYNAMIC);
-
-    // TODO uuid is missing
-
-    footer->checksum = be32_to_cpu(vpc_checksum(buf, HEADER_SIZE));
-
     // Write the footer (twice: at the beginning and at the end)
     block_size = 0x200000;
     num_bat_entries = (total_sectors + block_size / 512) / (block_size / 512);
@@ -624,7 +595,6 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
         }
     }
 
-
     // Prepare the Dynamic Disk Header
     memset(buf, 0, 1024);
 
@@ -653,6 +623,132 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
     ret = 0;
 
  fail:
+    return ret;
+}
+
+static int create_fixed_disk(int fd, uint8_t *buf, int64_t total_size)
+{
+    int ret = -EIO;
+
+    /* Add footer to total size */
+    total_size += 512;
+    if (ftruncate(fd, total_size) != 0) {
+        ret = -errno;
+        goto fail;
+    }
+    if (lseek(fd, -512, SEEK_END) < 0) {
+        goto fail;
+    }
+    if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE) {
+        goto fail;
+    }
+
+    ret = 0;
+
+ fail:
+    return ret;
+}
+
+static int vpc_create(const char *filename, QEMUOptionParameter *options)
+{
+    uint8_t buf[1024];
+    struct vhd_footer *footer = (struct vhd_footer *) buf;
+    QEMUOptionParameter *disk_type_param;
+    int fd, i;
+    uint16_t cyls = 0;
+    uint8_t heads = 0;
+    uint8_t secs_per_cyl = 0;
+    int64_t total_sectors;
+    int64_t total_size;
+    int disk_type;
+    int ret = -EIO;
+
+    /* Read out options */
+    total_size = get_option_parameter(options, BLOCK_OPT_SIZE)->value.n;
+
+    disk_type_param = get_option_parameter(options, BLOCK_OPT_SUBFMT);
+    if (disk_type_param && disk_type_param->value.s) {
+        if (!strcmp(disk_type_param->value.s, "dynamic")) {
+            disk_type = VHD_DYNAMIC;
+        } else if (!strcmp(disk_type_param->value.s, "fixed")) {
+            disk_type = VHD_FIXED;
+        } else {
+            return -EINVAL;
+        }
+    } else {
+        disk_type = VHD_DYNAMIC;
+    }
+
+    /* Create the file */
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+    if (fd < 0) {
+        return -EIO;
+    }
+
+    total_sectors = total_size / BDRV_SECTOR_SIZE;
+    if (disk_type == VHD_DYNAMIC) {
+        /* Calculate matching total_size and geometry. Increase the number of
+           sectors requested until we get enough (or fail). */
+        for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl;
+             i++) {
+            if (calculate_geometry(total_sectors + i,
+                                   &cyls, &heads, &secs_per_cyl)) {
+                ret = -EFBIG;
+                goto fail;
+            }
+        }
+    } else {
+        if (calculate_geometry(total_sectors, &cyls, &heads, &secs_per_cyl)) {
+            ret = -EFBIG;
+            goto fail;
+        }
+    }
+    total_sectors = (int64_t) cyls * heads * secs_per_cyl;
+
+    /* Prepare the Hard Disk Footer */
+    memset(buf, 0, 1024);
+
+    memcpy(footer->creator, "conectix", 8);
+    /* TODO Check if "qemu" creator_app is ok for VPC */
+    memcpy(footer->creator_app, "qemu", 4);
+    memcpy(footer->creator_os, "Wi2k", 4);
+
+    footer->features = be32_to_cpu(0x02);
+    footer->version = be32_to_cpu(0x00010000);
+    if (disk_type == VHD_DYNAMIC) {
+        footer->data_offset = be64_to_cpu(HEADER_SIZE);
+    } else {
+        footer->data_offset = be64_to_cpu(0xFFFFFFFFFFFFFFFFULL);
+    }
+    footer->timestamp = be32_to_cpu(time(NULL) - VHD_TIMESTAMP_BASE);
+
+    /* Version of Virtual PC 2007 */
+    footer->major = be16_to_cpu(0x0005);
+    footer->minor = be16_to_cpu(0x0003);
+    if (disk_type == VHD_DYNAMIC) {
+        footer->orig_size = be64_to_cpu(total_sectors * 512);
+        footer->size = be64_to_cpu(total_sectors * 512);
+    } else {
+        footer->orig_size = be64_to_cpu(total_size);
+        footer->size = be64_to_cpu(total_size);
+    }
+    footer->cyls = be16_to_cpu(cyls);
+    footer->heads = heads;
+    footer->secs_per_cyl = secs_per_cyl;
+
+    footer->type = be32_to_cpu(disk_type);
+
+    /* TODO uuid is missing */
+
+    footer->checksum = be32_to_cpu(vpc_checksum(buf, HEADER_SIZE));
+
+    if (disk_type == VHD_DYNAMIC) {
+        ret = create_dynamic_disk(fd, buf, total_sectors);
+    } else {
+        ret = create_fixed_disk(fd, buf, total_size);
+    }
+
+ fail:
     close(fd);
     return ret;
 }
@@ -675,6 +771,13 @@ static QEMUOptionParameter vpc_create_options[] = {
         .type = OPT_SIZE,
         .help = "Virtual disk size"
     },
+    {
+        .name = BLOCK_OPT_SUBFMT,
+        .type = OPT_STRING,
+        .help =
+            "Type of virtual hard disk format. Supported formats are "
+            "{dynamic (default) | fixed} "
+    },
     { NULL }
 };
 
commit f9dadc9855ae1554a98c53a10a3a962859992865
Author: Ronnie Sahlberg <ronniesahlberg at gmail.com>
Date:   Thu Jan 26 09:39:02 2012 +1100

    iSCSI: add configuration variables for iSCSI
    
    This patch adds configuration variables for iSCSI to set
    initiator-name to use when logging in to the target,
    which type of header-digest to negotiate with the target
    and username and password for CHAP authentication.
    
    This allows specifying a initiator-name either from the command line
    -iscsi initiator-name=iqn.2004-01.com.example:test
    or from a configuration file included with -readconfig
        [iscsi]
          initiator-name = iqn.2004-01.com.example:test
          header-digest = CRC32C|CRC32C-NONE|NONE-CRC32C|NONE
          user = CHAP username
          password = CHAP password
    
    If you use several different targets, you can also configure this on a per
    target basis by using a group name:
        [iscsi "iqn.target.name"]
        ...
    
    The configuration file can be read using -readconfig.
    Example :
    qemu-system-i386 -drive file=iscsi://127.0.0.1/iqn.ronnie.test/1
     -readconfig iscsi.conf
    
    Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/iscsi.c b/block/iscsi.c
index 938c568..bd3ca11 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -455,6 +455,109 @@ iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
     }
 }
 
+static int parse_chap(struct iscsi_context *iscsi, const char *target)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    const char *user = NULL;
+    const char *password = NULL;
+
+    list = qemu_find_opts("iscsi");
+    if (!list) {
+        return 0;
+    }
+
+    opts = qemu_opts_find(list, target);
+    if (opts == NULL) {
+        opts = QTAILQ_FIRST(&list->head);
+        if (!opts) {
+            return 0;
+        }
+    }
+
+    user = qemu_opt_get(opts, "user");
+    if (!user) {
+        return 0;
+    }
+
+    password = qemu_opt_get(opts, "password");
+    if (!password) {
+        error_report("CHAP username specified but no password was given");
+        return -1;
+    }
+
+    if (iscsi_set_initiator_username_pwd(iscsi, user, password)) {
+        error_report("Failed to set initiator username and password");
+        return -1;
+    }
+
+    return 0;
+}
+
+static void parse_header_digest(struct iscsi_context *iscsi, const char *target)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    const char *digest = NULL;
+
+    list = qemu_find_opts("iscsi");
+    if (!list) {
+        return;
+    }
+
+    opts = qemu_opts_find(list, target);
+    if (opts == NULL) {
+        opts = QTAILQ_FIRST(&list->head);
+        if (!opts) {
+            return;
+        }
+    }
+
+    digest = qemu_opt_get(opts, "header-digest");
+    if (!digest) {
+        return;
+    }
+
+    if (!strcmp(digest, "CRC32C")) {
+        iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C);
+    } else if (!strcmp(digest, "NONE")) {
+        iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE);
+    } else if (!strcmp(digest, "CRC32C-NONE")) {
+        iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C_NONE);
+    } else if (!strcmp(digest, "NONE-CRC32C")) {
+        iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
+    } else {
+        error_report("Invalid header-digest setting : %s", digest);
+    }
+}
+
+static char *parse_initiator_name(const char *target)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    const char *name = NULL;
+
+    list = qemu_find_opts("iscsi");
+    if (!list) {
+        return g_strdup("iqn.2008-11.org.linux-kvm");
+    }
+
+    opts = qemu_opts_find(list, target);
+    if (opts == NULL) {
+        opts = QTAILQ_FIRST(&list->head);
+        if (!opts) {
+            return g_strdup("iqn.2008-11.org.linux-kvm");
+        }
+    }
+
+    name = qemu_opt_get(opts, "initiator-name");
+    if (!name) {
+        return g_strdup("iqn.2008-11.org.linux-kvm");
+    }
+
+    return g_strdup(name);
+}
+
 /*
  * We support iscsi url's on the form
  * iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
@@ -465,6 +568,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
     struct iscsi_context *iscsi = NULL;
     struct iscsi_url *iscsi_url = NULL;
     struct IscsiTask task;
+    char *initiator_name = NULL;
     int ret;
 
     if ((BDRV_SECTOR_SIZE % 512) != 0) {
@@ -474,16 +578,6 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
         return -EINVAL;
     }
 
-    memset(iscsilun, 0, sizeof(IscsiLun));
-
-    /* Should really append the KVM name after the ':' here */
-    iscsi = iscsi_create_context("iqn.2008-11.org.linux-kvm:");
-    if (iscsi == NULL) {
-        error_report("iSCSI: Failed to create iSCSI context.");
-        ret = -ENOMEM;
-        goto failed;
-    }
-
     iscsi_url = iscsi_parse_full_url(iscsi, filename);
     if (iscsi_url == NULL) {
         error_report("Failed to parse URL : %s %s", filename,
@@ -492,6 +586,17 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
         goto failed;
     }
 
+    memset(iscsilun, 0, sizeof(IscsiLun));
+
+    initiator_name = parse_initiator_name(iscsi_url->target);
+
+    iscsi = iscsi_create_context(initiator_name);
+    if (iscsi == NULL) {
+        error_report("iSCSI: Failed to create iSCSI context.");
+        ret = -ENOMEM;
+        goto failed;
+    }
+
     if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
         error_report("iSCSI: Failed to set target name.");
         ret = -EINVAL;
@@ -507,6 +612,14 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
             goto failed;
         }
     }
+
+    /* check if we got CHAP username/password via the options */
+    if (parse_chap(iscsi, iscsi_url->target) != 0) {
+        error_report("iSCSI: Failed to set CHAP user/password");
+        ret = -EINVAL;
+        goto failed;
+    }
+
     if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) {
         error_report("iSCSI: Failed to set session type to normal.");
         ret = -EINVAL;
@@ -515,6 +628,9 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
 
     iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
 
+    /* check if we got HEADER_DIGEST via the options */
+    parse_header_digest(iscsi, iscsi_url->target);
+
     task.iscsilun = iscsilun;
     task.status = 0;
     task.complete = 0;
@@ -548,6 +664,9 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
     return 0;
 
 failed:
+    if (initiator_name != NULL) {
+        g_free(initiator_name);
+    }
     if (iscsi_url != NULL) {
         iscsi_destroy_url(iscsi_url);
     }
diff --git a/qemu-config.c b/qemu-config.c
index b030205..e980fd6 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -118,6 +118,32 @@ static QemuOptsList qemu_drive_opts = {
     },
 };
 
+static QemuOptsList qemu_iscsi_opts = {
+    .name = "iscsi",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head),
+    .desc = {
+        {
+            .name = "user",
+            .type = QEMU_OPT_STRING,
+            .help = "username for CHAP authentication to target",
+        },{
+            .name = "password",
+            .type = QEMU_OPT_STRING,
+            .help = "password for CHAP authentication to target",
+        },{
+            .name = "header-digest",
+            .type = QEMU_OPT_STRING,
+            .help = "HeaderDigest setting. "
+                    "{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}",
+        },{
+            .name = "initiator-name",
+            .type = QEMU_OPT_STRING,
+            .help = "Initiator iqn name to use when connecting",
+        },
+        { /* end of list */ }
+    },
+};
+
 static QemuOptsList qemu_chardev_opts = {
     .name = "chardev",
     .implied_opt_name = "backend",
@@ -580,6 +606,7 @@ static QemuOptsList *vm_config_groups[32] = {
     &qemu_option_rom_opts,
     &qemu_machine_opts,
     &qemu_boot_opts,
+    &qemu_iscsi_opts,
     NULL,
 };
 
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 11f4166..83b2ad5 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -730,6 +730,57 @@ export LIBISCSI_CHAP_PASSWORD=<password>
 iscsi://<host>/<target-iqn-name>/<lun>
 @end example
 
+Various session related parameters can be set via special options, either
+in a configuration file provided via '-readconfig' or directly on the
+command line.
+
+ at example
+Setting a specific initiator name to use when logging in to the target
+-iscsi initiator-name=iqn.qemu.test:my-initiator
+ at end example
+
+ at example
+Controlling which type of header digest to negotiate with the target
+-iscsi header-digest=CRC32C|CRC32C-NONE|NONE-CRC32C|NONE
+ at end example
+
+These can also be set via a configuration file
+ at example
+[iscsi]
+  user = "CHAP username"
+  password = "CHAP password"
+  initiator-name = "iqn.qemu.test:my-initiator"
+  # header digest is one of CRC32C|CRC32C-NONE|NONE-CRC32C|NONE
+  header-digest = "CRC32C"
+ at end example
+
+
+Setting the target name allows different options for different targets
+ at example
+[iscsi "iqn.target.name"]
+  user = "CHAP username"
+  password = "CHAP password"
+  initiator-name = "iqn.qemu.test:my-initiator"
+  # header digest is one of CRC32C|CRC32C-NONE|NONE-CRC32C|NONE
+  header-digest = "CRC32C"
+ at end example
+
+
+Howto use a configuration file to set iSCSI configuration options:
+ at example
+cat >iscsi.conf <<EOF
+[iscsi]
+  user = "me"
+  password = "my password"
+  initiator-name = "iqn.qemu.test:my-initiator"
+  header-digest = "CRC32C"
+EOF
+
+qemu-system-i386 -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \
+    -readconfig iscsi.conf
+ at end example
+
+
 Howto set up a simple iSCSI target on loopback and accessing it via QEMU:
 @example
 This example shows how to set up an iSCSI target with one CDROM and one DISK
@@ -744,7 +795,8 @@ tgtadm --lld iscsi --mode logicalunit --op new --tid 1 --lun 2 \
     -b /IMAGES/cd.iso --device-type=cd
 tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL
 
-qemu-system-i386 -boot d -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \
+qemu-system-i386 -iscsi initiator-name=iqn.qemu.test:my-initiator \
+    -boot d -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \
     -cdrom iscsi://127.0.0.1/iqn.qemu.test/2
 @end example
 
diff --git a/qemu-options.hx b/qemu-options.hx
index f577cc8..42d22ae 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1829,24 +1829,32 @@ Syntax for specifying iSCSI LUNs is
 
 Example (without authentication):
 @example
-qemu -cdrom iscsi://192.0.2.1/iqn.2001-04.com.example/2 \
---drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
+qemu -iscsi initiator-name=iqn.2001-04.com.example:my-initiator \
+-cdrom iscsi://192.0.2.1/iqn.2001-04.com.example/2 \
+-drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
 @end example
 
 Example (CHAP username/password via URL):
 @example
-qemu --drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1
+qemu -drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1
 @end example
 
 Example (CHAP username/password via environment variables):
 @example
 LIBISCSI_CHAP_USERNAME="user" \
 LIBISCSI_CHAP_PASSWORD="password" \
-qemu --drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
+qemu -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
 @end example
 
 iSCSI support is an optional feature of QEMU and only available when
 compiled and linked against libiscsi.
+ETEXI
+DEF("iscsi", HAS_ARG, QEMU_OPTION_iscsi,
+    "-iscsi [user=user][,password=password]\n"
+    "       [,header-digest=CRC32C|CR32C-NONE|NONE-CRC32C|NONE\n"
+    "       [,initiator-name=iqn]\n"
+    "                iSCSI session parameters\n", QEMU_ARCH_ALL)
+STEXI
 
 @item NBD
 QEMU supports NBD (Network Block Devices) both using TCP protocol as well
diff --git a/vl.c b/vl.c
index 63dd725..0c66071 100644
--- a/vl.c
+++ b/vl.c
@@ -2529,6 +2529,14 @@ int main(int argc, char **argv, char **envp)
                     exit(1);
                 }
                 break;
+#ifdef CONFIG_LIBISCSI
+            case QEMU_OPTION_iscsi:
+                opts = qemu_opts_parse(qemu_find_opts("iscsi"), optarg, 0);
+                if (!opts) {
+                    exit(1);
+                }
+                break;
+#endif
 #ifdef CONFIG_SLIRP
             case QEMU_OPTION_tftp:
                 legacy_tftp_prefix = optarg;
commit 71b58b82dac1e1dc5e08a005a14bbcafecbd9e2a
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Tue Feb 7 13:27:29 2012 +0000

    qemu-io: add write -z option for bdrv_co_write_zeroes
    
    Extend the qemu-io write command with the -z option to call
    bdrv_co_write_zeroes().  Exposing the zero write interface from qemu-io
    allows us to write tests that exercise this new block layer interface.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-io.c b/qemu-io.c
index d4a5fcb..0249be4 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -218,6 +218,51 @@ static int do_pwrite(char *buf, int64_t offset, int count, int *total)
     return 1;
 }
 
+typedef struct {
+    int64_t offset;
+    int count;
+    int *total;
+    int ret;
+    bool done;
+} CoWriteZeroes;
+
+static void coroutine_fn co_write_zeroes_entry(void *opaque)
+{
+    CoWriteZeroes *data = opaque;
+
+    data->ret = bdrv_co_write_zeroes(bs, data->offset / BDRV_SECTOR_SIZE,
+                                     data->count / BDRV_SECTOR_SIZE);
+    data->done = true;
+    if (data->ret < 0) {
+        *data->total = data->ret;
+        return;
+    }
+
+    *data->total = data->count;
+}
+
+static int do_co_write_zeroes(int64_t offset, int count, int *total)
+{
+    Coroutine *co;
+    CoWriteZeroes data = {
+        .offset = offset,
+        .count  = count,
+        .total  = total,
+        .done   = false,
+    };
+
+    co = qemu_coroutine_create(co_write_zeroes_entry);
+    qemu_coroutine_enter(co, &data);
+    while (!data.done) {
+        qemu_aio_wait();
+    }
+    if (data.ret < 0) {
+        return data.ret;
+    } else {
+        return 1;
+    }
+}
+
 static int do_load_vmstate(char *buf, int64_t offset, int count, int *total)
 {
     *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
@@ -643,6 +688,7 @@ static void write_help(void)
 " -P, -- use different pattern to fill file\n"
 " -C, -- report statistics in a machine parsable format\n"
 " -q, -- quiet mode, do not show I/O statistics\n"
+" -z, -- write zeroes using bdrv_co_write_zeroes\n"
 "\n");
 }
 
@@ -654,7 +700,7 @@ static const cmdinfo_t write_cmd = {
     .cfunc      = write_f,
     .argmin     = 2,
     .argmax     = -1,
-    .args       = "[-abCpq] [-P pattern ] off len",
+    .args       = "[-bCpqz] [-P pattern ] off len",
     .oneline    = "writes a number of bytes at a specified offset",
     .help       = write_help,
 };
@@ -662,16 +708,16 @@ static const cmdinfo_t write_cmd = {
 static int write_f(int argc, char **argv)
 {
     struct timeval t1, t2;
-    int Cflag = 0, pflag = 0, qflag = 0, bflag = 0;
+    int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0;
     int c, cnt;
-    char *buf;
+    char *buf = NULL;
     int64_t offset;
     int count;
     /* Some compilers get confused and warn if this is not initialized.  */
     int total = 0;
     int pattern = 0xcd;
 
-    while ((c = getopt(argc, argv, "bCpP:q")) != EOF) {
+    while ((c = getopt(argc, argv, "bCpP:qz")) != EOF) {
         switch (c) {
         case 'b':
             bflag = 1;
@@ -683,6 +729,7 @@ static int write_f(int argc, char **argv)
             pflag = 1;
             break;
         case 'P':
+            Pflag = 1;
             pattern = parse_pattern(optarg);
             if (pattern < 0) {
                 return 0;
@@ -691,6 +738,9 @@ static int write_f(int argc, char **argv)
         case 'q':
             qflag = 1;
             break;
+        case 'z':
+            zflag = 1;
+            break;
         default:
             return command_usage(&write_cmd);
         }
@@ -700,8 +750,13 @@ static int write_f(int argc, char **argv)
         return command_usage(&write_cmd);
     }
 
-    if (bflag && pflag) {
-        printf("-b and -p cannot be specified at the same time\n");
+    if (bflag + pflag + zflag > 1) {
+        printf("-b, -p, or -z cannot be specified at the same time\n");
+        return 0;
+    }
+
+    if (zflag && Pflag) {
+        printf("-z and -P cannot be specified at the same time\n");
         return 0;
     }
 
@@ -732,13 +787,17 @@ static int write_f(int argc, char **argv)
         }
     }
 
-    buf = qemu_io_alloc(count, pattern);
+    if (!zflag) {
+        buf = qemu_io_alloc(count, pattern);
+    }
 
     gettimeofday(&t1, NULL);
     if (pflag) {
         cnt = do_pwrite(buf, offset, count, &total);
     } else if (bflag) {
         cnt = do_save_vmstate(buf, offset, count, &total);
+    } else if (zflag) {
+        cnt = do_co_write_zeroes(offset, count, &total);
     } else {
         cnt = do_write(buf, offset, count, &total);
     }
@@ -758,7 +817,9 @@ static int write_f(int argc, char **argv)
     print_report("wrote", &t2, offset, count, total, cnt, Cflag);
 
 out:
-    qemu_io_free(buf);
+    if (!zflag) {
+        qemu_io_free(buf);
+    }
 
     return 0;
 }
commit 0e71be1932adfad27d564675f89a468fc8b92b1f
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Tue Feb 7 13:27:28 2012 +0000

    qed: add .bdrv_co_write_zeroes() support
    
    Zero writes are a dedicated interface for writing regions of zeroes into
    the image file.  If clusters are not yet allocated it is possible to use
    an efficient metadata representation which keeps the image file compact
    and does not store individual zero bytes.
    
    Implementing this for the QED image format is fairly straightforward.
    The only issue is that when a zero write touches an existing cluster we
    have to allocate a bounce buffer and perform a regular write.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qed.c b/block/qed.c
index b66dd17..a041d31 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -875,6 +875,12 @@ static void qed_aio_complete(QEDAIOCB *acb, int ret)
     qemu_iovec_destroy(&acb->cur_qiov);
     qed_unref_l2_cache_entry(acb->request.l2_table);
 
+    /* Free the buffer we may have allocated for zero writes */
+    if (acb->flags & QED_AIOCB_ZERO) {
+        qemu_vfree(acb->qiov->iov[0].iov_base);
+        acb->qiov->iov[0].iov_base = NULL;
+    }
+
     /* Arrange for a bh to invoke the completion function */
     acb->bh_ret = ret;
     acb->bh = qemu_bh_new(qed_aio_complete_bh, acb);
@@ -941,9 +947,8 @@ static void qed_aio_write_l1_update(void *opaque, int ret)
 /**
  * Update L2 table with new cluster offsets and write them out
  */
-static void qed_aio_write_l2_update(void *opaque, int ret)
+static void qed_aio_write_l2_update(QEDAIOCB *acb, int ret, uint64_t offset)
 {
-    QEDAIOCB *acb = opaque;
     BDRVQEDState *s = acb_to_s(acb);
     bool need_alloc = acb->find_cluster_ret == QED_CLUSTER_L1;
     int index;
@@ -959,7 +964,7 @@ static void qed_aio_write_l2_update(void *opaque, int ret)
 
     index = qed_l2_index(s, acb->cur_pos);
     qed_update_l2_table(s, acb->request.l2_table->table, index, acb->cur_nclusters,
-                         acb->cur_cluster);
+                         offset);
 
     if (need_alloc) {
         /* Write out the whole new L2 table */
@@ -976,6 +981,12 @@ err:
     qed_aio_complete(acb, ret);
 }
 
+static void qed_aio_write_l2_update_cb(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    qed_aio_write_l2_update(acb, ret, acb->cur_cluster);
+}
+
 /**
  * Flush new data clusters before updating the L2 table
  *
@@ -990,7 +1001,7 @@ static void qed_aio_write_flush_before_l2_update(void *opaque, int ret)
     QEDAIOCB *acb = opaque;
     BDRVQEDState *s = acb_to_s(acb);
 
-    if (!bdrv_aio_flush(s->bs->file, qed_aio_write_l2_update, opaque)) {
+    if (!bdrv_aio_flush(s->bs->file, qed_aio_write_l2_update_cb, opaque)) {
         qed_aio_complete(acb, -EIO);
     }
 }
@@ -1019,7 +1030,7 @@ static void qed_aio_write_main(void *opaque, int ret)
         if (s->bs->backing_hd) {
             next_fn = qed_aio_write_flush_before_l2_update;
         } else {
-            next_fn = qed_aio_write_l2_update;
+            next_fn = qed_aio_write_l2_update_cb;
         }
     }
 
@@ -1081,6 +1092,18 @@ static bool qed_should_set_need_check(BDRVQEDState *s)
     return !(s->header.features & QED_F_NEED_CHECK);
 }
 
+static void qed_aio_write_zero_cluster(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+
+    if (ret) {
+        qed_aio_complete(acb, ret);
+        return;
+    }
+
+    qed_aio_write_l2_update(acb, 0, 1);
+}
+
 /**
  * Write new data cluster
  *
@@ -1092,6 +1115,7 @@ static bool qed_should_set_need_check(BDRVQEDState *s)
 static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
 {
     BDRVQEDState *s = acb_to_s(acb);
+    BlockDriverCompletionFunc *cb;
 
     /* Cancel timer when the first allocating request comes in */
     if (QSIMPLEQ_EMPTY(&s->allocating_write_reqs)) {
@@ -1109,14 +1133,26 @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
 
     acb->cur_nclusters = qed_bytes_to_clusters(s,
             qed_offset_into_cluster(s, acb->cur_pos) + len);
-    acb->cur_cluster = qed_alloc_clusters(s, acb->cur_nclusters);
     qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
 
+    if (acb->flags & QED_AIOCB_ZERO) {
+        /* Skip ahead if the clusters are already zero */
+        if (acb->find_cluster_ret == QED_CLUSTER_ZERO) {
+            qed_aio_next_io(acb, 0);
+            return;
+        }
+
+        cb = qed_aio_write_zero_cluster;
+    } else {
+        cb = qed_aio_write_prefill;
+        acb->cur_cluster = qed_alloc_clusters(s, acb->cur_nclusters);
+    }
+
     if (qed_should_set_need_check(s)) {
         s->header.features |= QED_F_NEED_CHECK;
-        qed_write_header(s, qed_aio_write_prefill, acb);
+        qed_write_header(s, cb, acb);
     } else {
-        qed_aio_write_prefill(acb, 0);
+        cb(acb, 0);
     }
 }
 
@@ -1131,6 +1167,16 @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
  */
 static void qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
 {
+    /* Allocate buffer for zero writes */
+    if (acb->flags & QED_AIOCB_ZERO) {
+        struct iovec *iov = acb->qiov->iov;
+
+        if (!iov->iov_base) {
+            iov->iov_base = qemu_blockalign(acb->common.bs, iov->iov_len);
+            memset(iov->iov_base, 0, iov->iov_len);
+        }
+    }
+
     /* Calculate the I/O vector */
     acb->cur_cluster = offset;
     qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
@@ -1311,6 +1357,53 @@ static BlockDriverAIOCB *bdrv_qed_aio_flush(BlockDriverState *bs,
     return bdrv_aio_flush(bs->file, cb, opaque);
 }
 
+typedef struct {
+    Coroutine *co;
+    int ret;
+    bool done;
+} QEDWriteZeroesCB;
+
+static void coroutine_fn qed_co_write_zeroes_cb(void *opaque, int ret)
+{
+    QEDWriteZeroesCB *cb = opaque;
+
+    cb->done = true;
+    cb->ret = ret;
+    if (cb->co) {
+        qemu_coroutine_enter(cb->co, NULL);
+    }
+}
+
+static int coroutine_fn bdrv_qed_co_write_zeroes(BlockDriverState *bs,
+                                                 int64_t sector_num,
+                                                 int nb_sectors)
+{
+    BlockDriverAIOCB *blockacb;
+    QEDWriteZeroesCB cb = { .done = false };
+    QEMUIOVector qiov;
+    struct iovec iov;
+
+    /* Zero writes start without an I/O buffer.  If a buffer becomes necessary
+     * then it will be allocated during request processing.
+     */
+    iov.iov_base = NULL,
+    iov.iov_len  = nb_sectors * BDRV_SECTOR_SIZE,
+
+    qemu_iovec_init_external(&qiov, &iov, 1);
+    blockacb = qed_aio_setup(bs, sector_num, &qiov, nb_sectors,
+                             qed_co_write_zeroes_cb, &cb,
+                             QED_AIOCB_WRITE | QED_AIOCB_ZERO);
+    if (!blockacb) {
+        return -EIO;
+    }
+    if (!cb.done) {
+        cb.co = qemu_coroutine_self();
+        qemu_coroutine_yield();
+    }
+    assert(cb.done);
+    return cb.ret;
+}
+
 static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset)
 {
     BDRVQEDState *s = bs->opaque;
@@ -1470,6 +1563,7 @@ static BlockDriver bdrv_qed = {
     .bdrv_aio_readv           = bdrv_qed_aio_readv,
     .bdrv_aio_writev          = bdrv_qed_aio_writev,
     .bdrv_aio_flush           = bdrv_qed_aio_flush,
+    .bdrv_co_write_zeroes     = bdrv_qed_co_write_zeroes,
     .bdrv_truncate            = bdrv_qed_truncate,
     .bdrv_getlength           = bdrv_qed_getlength,
     .bdrv_get_info            = bdrv_qed_get_info,
diff --git a/block/qed.h b/block/qed.h
index abed147..62624a1 100644
--- a/block/qed.h
+++ b/block/qed.h
@@ -125,6 +125,7 @@ typedef struct QEDRequest {
 
 enum {
     QED_AIOCB_WRITE = 0x0001,       /* read or write? */
+    QED_AIOCB_ZERO  = 0x0002,       /* zero write, used with QED_AIOCB_WRITE */
 };
 
 typedef struct QEDAIOCB {
commit 6e4f59bd0d69f0a7aa4010b49a5c49a01987b9d8
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Tue Feb 7 13:27:27 2012 +0000

    qed: replace is_write with flags field
    
    Per-request attributes like read/write are currently implemented as bool
    fields in the QEDAIOCB struct.  This becomes unwiedly as the number of
    attributes grows.  For example, the qed_aio_setup() function would have
    to take multiple bool arguments and at call sites it would be hard to
    distinguish the meaning of each bool.
    
    Instead use a flags field with bitmask constants.  This will be used
    when zero write support is added.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qed.c b/block/qed.c
index 8da3ebe..b66dd17 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -1233,8 +1233,8 @@ static void qed_aio_next_io(void *opaque, int ret)
 {
     QEDAIOCB *acb = opaque;
     BDRVQEDState *s = acb_to_s(acb);
-    QEDFindClusterFunc *io_fn =
-        acb->is_write ? qed_aio_write_data : qed_aio_read_data;
+    QEDFindClusterFunc *io_fn = (acb->flags & QED_AIOCB_WRITE) ?
+                                qed_aio_write_data : qed_aio_read_data;
 
     trace_qed_aio_next_io(s, acb, ret, acb->cur_pos + acb->cur_qiov.size);
 
@@ -1264,14 +1264,14 @@ static BlockDriverAIOCB *qed_aio_setup(BlockDriverState *bs,
                                        int64_t sector_num,
                                        QEMUIOVector *qiov, int nb_sectors,
                                        BlockDriverCompletionFunc *cb,
-                                       void *opaque, bool is_write)
+                                       void *opaque, int flags)
 {
     QEDAIOCB *acb = qemu_aio_get(&qed_aio_pool, bs, cb, opaque);
 
     trace_qed_aio_setup(bs->opaque, acb, sector_num, nb_sectors,
-                         opaque, is_write);
+                        opaque, flags);
 
-    acb->is_write = is_write;
+    acb->flags = flags;
     acb->finished = NULL;
     acb->qiov = qiov;
     acb->qiov_offset = 0;
@@ -1291,7 +1291,7 @@ static BlockDriverAIOCB *bdrv_qed_aio_readv(BlockDriverState *bs,
                                             BlockDriverCompletionFunc *cb,
                                             void *opaque)
 {
-    return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, false);
+    return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
 }
 
 static BlockDriverAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs,
@@ -1300,7 +1300,8 @@ static BlockDriverAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs,
                                              BlockDriverCompletionFunc *cb,
                                              void *opaque)
 {
-    return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, true);
+    return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb,
+                         opaque, QED_AIOCB_WRITE);
 }
 
 static BlockDriverAIOCB *bdrv_qed_aio_flush(BlockDriverState *bs,
diff --git a/block/qed.h b/block/qed.h
index 62cbd3b..abed147 100644
--- a/block/qed.h
+++ b/block/qed.h
@@ -123,12 +123,16 @@ typedef struct QEDRequest {
     CachedL2Table *l2_table;
 } QEDRequest;
 
+enum {
+    QED_AIOCB_WRITE = 0x0001,       /* read or write? */
+};
+
 typedef struct QEDAIOCB {
     BlockDriverAIOCB common;
     QEMUBH *bh;
     int bh_ret;                     /* final return status for completion bh */
     QSIMPLEQ_ENTRY(QEDAIOCB) next;  /* next request */
-    bool is_write;                  /* false - read, true - write */
+    int flags;                      /* QED_AIOCB_* bits ORed together */
     bool *finished;                 /* signal for cancel completion */
     uint64_t end_pos;               /* request end on block device, in bytes */
 
diff --git a/trace-events b/trace-events
index 3372087..9b26ce2 100644
--- a/trace-events
+++ b/trace-events
@@ -321,7 +321,7 @@ qed_need_check_timer_cb(void *s) "s %p"
 qed_start_need_check_timer(void *s) "s %p"
 qed_cancel_need_check_timer(void *s) "s %p"
 qed_aio_complete(void *s, void *acb, int ret) "s %p acb %p ret %d"
-qed_aio_setup(void *s, void *acb, int64_t sector_num, int nb_sectors, void *opaque, int is_write) "s %p acb %p sector_num %"PRId64" nb_sectors %d opaque %p is_write %d"
+qed_aio_setup(void *s, void *acb, int64_t sector_num, int nb_sectors, void *opaque, int flags) "s %p acb %p sector_num %"PRId64" nb_sectors %d opaque %p flags %#x"
 qed_aio_next_io(void *s, void *acb, int ret, uint64_t cur_pos) "s %p acb %p ret %d cur_pos %"PRIu64
 qed_aio_read_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
 qed_aio_write_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
commit 79c053bde9fa40595670ae274d047da07f1df88c
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Tue Feb 7 13:27:26 2012 +0000

    block: perform zero-detection during copy-on-read
    
    Copy-on-Read populates the image file with data read from a backing
    image.  In order to avoid bloating the image file when all zeroes are
    read we should scan the buffer and perform an optimized zero write
    operation.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index c9fa5c1..ae297bb 100644
--- a/block.c
+++ b/block.c
@@ -1517,6 +1517,7 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
      */
     void *bounce_buffer;
 
+    BlockDriver *drv = bs->drv;
     struct iovec iov;
     QEMUIOVector bounce_qiov;
     int64_t cluster_sector_num;
@@ -1537,14 +1538,21 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
     iov.iov_base = bounce_buffer = qemu_blockalign(bs, iov.iov_len);
     qemu_iovec_init_external(&bounce_qiov, &iov, 1);
 
-    ret = bs->drv->bdrv_co_readv(bs, cluster_sector_num, cluster_nb_sectors,
-                                 &bounce_qiov);
+    ret = drv->bdrv_co_readv(bs, cluster_sector_num, cluster_nb_sectors,
+                             &bounce_qiov);
     if (ret < 0) {
         goto err;
     }
 
-    ret = bs->drv->bdrv_co_writev(bs, cluster_sector_num, cluster_nb_sectors,
+    if (drv->bdrv_co_write_zeroes &&
+        buffer_is_zero(bounce_buffer, iov.iov_len)) {
+        ret = drv->bdrv_co_write_zeroes(bs, cluster_sector_num,
+                                        cluster_nb_sectors);
+    } else {
+        ret = drv->bdrv_co_writev(bs, cluster_sector_num, cluster_nb_sectors,
                                   &bounce_qiov);
+    }
+
     if (ret < 0) {
         /* It might be okay to ignore write errors for guest requests.  If this
          * is a deliberate copy-on-read then we don't want to ignore the error.
commit f08f2ddae078e8a7683f8b16da8e0cc3029c7b89
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Tue Feb 7 13:27:25 2012 +0000

    block: add .bdrv_co_write_zeroes() interface
    
    The ability to zero regions of an image file is a useful primitive for
    higher-level features such as image streaming or zero write detection.
    
    Image formats may support an optimized metadata representation instead
    of writing zeroes into the image file.  This allows zero writes to be
    potentially faster than regular write operations and also preserve
    sparseness of the image file.
    
    The .bdrv_co_write_zeroes() interface should be implemented by block
    drivers that wish to provide efficient zeroing.
    
    Note that this operation is different from the discard operation, which
    may leave the contents of the region indeterminate.  That means
    discarded blocks are not guaranteed to contain zeroes and may contain
    junk data instead.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 3621d11..c9fa5c1 100644
--- a/block.c
+++ b/block.c
@@ -50,6 +50,7 @@
 
 typedef enum {
     BDRV_REQ_COPY_ON_READ = 0x1,
+    BDRV_REQ_ZERO_WRITE   = 0x2,
 } BdrvRequestFlags;
 
 static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
@@ -69,7 +70,8 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
     int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
     BdrvRequestFlags flags);
 static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
-    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
+    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
+    BdrvRequestFlags flags);
 static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
                                                int64_t sector_num,
                                                QEMUIOVector *qiov,
@@ -1300,7 +1302,7 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque)
                                      rwco->nb_sectors, rwco->qiov, 0);
     } else {
         rwco->ret = bdrv_co_do_writev(rwco->bs, rwco->sector_num,
-                                      rwco->nb_sectors, rwco->qiov);
+                                      rwco->nb_sectors, rwco->qiov, 0);
     }
 }
 
@@ -1639,11 +1641,37 @@ int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs,
                             BDRV_REQ_COPY_ON_READ);
 }
 
+static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
+    int64_t sector_num, int nb_sectors)
+{
+    BlockDriver *drv = bs->drv;
+    QEMUIOVector qiov;
+    struct iovec iov;
+    int ret;
+
+    /* First try the efficient write zeroes operation */
+    if (drv->bdrv_co_write_zeroes) {
+        return drv->bdrv_co_write_zeroes(bs, sector_num, nb_sectors);
+    }
+
+    /* Fall back to bounce buffer if write zeroes is unsupported */
+    iov.iov_len  = nb_sectors * BDRV_SECTOR_SIZE;
+    iov.iov_base = qemu_blockalign(bs, iov.iov_len);
+    memset(iov.iov_base, 0, iov.iov_len);
+    qemu_iovec_init_external(&qiov, &iov, 1);
+
+    ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, &qiov);
+
+    qemu_vfree(iov.iov_base);
+    return ret;
+}
+
 /*
  * Handle a write request in coroutine context
  */
 static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
-    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
+    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
+    BdrvRequestFlags flags)
 {
     BlockDriver *drv = bs->drv;
     BdrvTrackedRequest req;
@@ -1670,7 +1698,11 @@ static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
 
     tracked_request_begin(&req, bs, sector_num, nb_sectors, true);
 
-    ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
+    if (flags & BDRV_REQ_ZERO_WRITE) {
+        ret = bdrv_co_do_write_zeroes(bs, sector_num, nb_sectors);
+    } else {
+        ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
+    }
 
     if (bs->dirty_bitmap) {
         set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
@@ -1690,7 +1722,16 @@ int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
 {
     trace_bdrv_co_writev(bs, sector_num, nb_sectors);
 
-    return bdrv_co_do_writev(bs, sector_num, nb_sectors, qiov);
+    return bdrv_co_do_writev(bs, sector_num, nb_sectors, qiov, 0);
+}
+
+int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs,
+                                      int64_t sector_num, int nb_sectors)
+{
+    trace_bdrv_co_write_zeroes(bs, sector_num, nb_sectors);
+
+    return bdrv_co_do_writev(bs, sector_num, nb_sectors, NULL,
+                             BDRV_REQ_ZERO_WRITE);
 }
 
 /**
@@ -3192,7 +3233,7 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque)
             acb->req.nb_sectors, acb->req.qiov, 0);
     } else {
         acb->req.error = bdrv_co_do_writev(bs, acb->req.sector,
-            acb->req.nb_sectors, acb->req.qiov);
+            acb->req.nb_sectors, acb->req.qiov, 0);
     }
 
     acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
diff --git a/block.h b/block.h
index cae289b..60ea730 100644
--- a/block.h
+++ b/block.h
@@ -146,6 +146,14 @@ int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs,
     int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
 int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
     int nb_sectors, QEMUIOVector *qiov);
+/*
+ * Efficiently zero a region of the disk image.  Note that this is a regular
+ * I/O request like read or write and should have a reasonable size.  This
+ * function is not suitable for zeroing the entire image in a single request
+ * because it may allocate memory for the entire region.
+ */
+int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
+    int nb_sectors);
 int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t sector_num,
     int nb_sectors, int *pnum);
 BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
diff --git a/block_int.h b/block_int.h
index 7be2988..7946cf6 100644
--- a/block_int.h
+++ b/block_int.h
@@ -131,6 +131,14 @@ struct BlockDriver {
         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
     int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs,
         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
+    /*
+     * Efficiently zero a region of the disk image.  Typically an image format
+     * would use a compact metadata representation to implement this.  This
+     * function pointer may be NULL and .bdrv_co_writev() will be called
+     * instead.
+     */
+    int coroutine_fn (*bdrv_co_write_zeroes)(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors);
     int coroutine_fn (*bdrv_co_discard)(BlockDriverState *bs,
         int64_t sector_num, int nb_sectors);
     int coroutine_fn (*bdrv_co_is_allocated)(BlockDriverState *bs,
diff --git a/trace-events b/trace-events
index 5d05749..3372087 100644
--- a/trace-events
+++ b/trace-events
@@ -67,6 +67,7 @@ bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
 bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
 bdrv_co_copy_on_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
 bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
+bdrv_co_write_zeroes(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
 bdrv_co_io_em(void *bs, int64_t sector_num, int nb_sectors, int is_write, void *acb) "bs %p sector_num %"PRId64" nb_sectors %d is_write %d acb %p"
 bdrv_co_do_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t cluster_sector_num, int cluster_nb_sectors) "bs %p sector_num %"PRId64" nb_sectors %d cluster_sector_num %"PRId64" cluster_nb_sectors %d"
 
commit 1a6d39fd71ddf90c5b76026cac4d5ff51fbaf8d8
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Tue Feb 7 13:27:24 2012 +0000

    cutils: extract buffer_is_zero() from qemu-img.c
    
    The qemu-img.c:is_not_zero() function checks if a buffer contains all
    zeroes.  This function will come in handy for zero-detection in the
    block layer, so clean it up and move it to cutils.c.
    
    Note that the function now returns true if the buffer is all zeroes.
    This avoids the double-negatives (i.e. !is_not_zero()) that the old
    function can cause in callers.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/cutils.c b/cutils.c
index a6ffd46..af308cd 100644
--- a/cutils.c
+++ b/cutils.c
@@ -303,6 +303,41 @@ void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count,
     }
 }
 
+/*
+ * Checks if a buffer is all zeroes
+ *
+ * Attention! The len must be a multiple of 4 * sizeof(long) due to
+ * restriction of optimizations in this function.
+ */
+bool buffer_is_zero(const void *buf, size_t len)
+{
+    /*
+     * Use long as the biggest available internal data type that fits into the
+     * CPU register and unroll the loop to smooth out the effect of memory
+     * latency.
+     */
+
+    size_t i;
+    long d0, d1, d2, d3;
+    const long * const data = buf;
+
+    assert(len % (4 * sizeof(long)) == 0);
+    len /= sizeof(long);
+
+    for (i = 0; i < len; i += 4) {
+        d0 = data[i + 0];
+        d1 = data[i + 1];
+        d2 = data[i + 2];
+        d3 = data[i + 3];
+
+        if (d0 || d1 || d2 || d3) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
 #ifndef _WIN32
 /* Sets a specific flag */
 int fcntl_setfl(int fd, int flag)
diff --git a/qemu-common.h b/qemu-common.h
index 9b997f8..c5e9cad 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -335,6 +335,8 @@ void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count);
 void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count,
                             size_t skip);
 
+bool buffer_is_zero(const void *buf, size_t len);
+
 void qemu_progress_init(int enabled, float min_skip);
 void qemu_progress_end(void);
 void qemu_progress_print(float delta, int max);
diff --git a/qemu-img.c b/qemu-img.c
index 01cc0d3..c4bcf41 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -515,40 +515,6 @@ static int img_commit(int argc, char **argv)
 }
 
 /*
- * Checks whether the sector is not a zero sector.
- *
- * Attention! The len must be a multiple of 4 * sizeof(long) due to
- * restriction of optimizations in this function.
- */
-static int is_not_zero(const uint8_t *sector, int len)
-{
-    /*
-     * Use long as the biggest available internal data type that fits into the
-     * CPU register and unroll the loop to smooth out the effect of memory
-     * latency.
-     */
-
-    int i;
-    long d0, d1, d2, d3;
-    const long * const data = (const long *) sector;
-
-    len /= sizeof(long);
-
-    for(i = 0; i < len; i += 4) {
-        d0 = data[i + 0];
-        d1 = data[i + 1];
-        d2 = data[i + 2];
-        d3 = data[i + 3];
-
-        if (d0 || d1 || d2 || d3) {
-            return 1;
-        }
-    }
-
-    return 0;
-}
-
-/*
  * Returns true iff the first sector pointed to by 'buf' contains at least
  * a non-NUL byte.
  *
@@ -557,20 +523,22 @@ static int is_not_zero(const uint8_t *sector, int len)
  */
 static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
 {
-    int v, i;
+    bool is_zero;
+    int i;
 
     if (n <= 0) {
         *pnum = 0;
         return 0;
     }
-    v = is_not_zero(buf, 512);
+    is_zero = buffer_is_zero(buf, 512);
     for(i = 1; i < n; i++) {
         buf += 512;
-        if (v != is_not_zero(buf, 512))
+        if (is_zero != buffer_is_zero(buf, 512)) {
             break;
+        }
     }
     *pnum = i;
-    return v;
+    return !is_zero;
 }
 
 /*
@@ -955,7 +923,7 @@ static int img_convert(int argc, char **argv)
             if (n < cluster_sectors) {
                 memset(buf + n * 512, 0, cluster_size - n * 512);
             }
-            if (is_not_zero(buf, cluster_size)) {
+            if (!buffer_is_zero(buf, cluster_size)) {
                 ret = bdrv_write_compressed(out_bs, sector_num, buf,
                                             cluster_sectors);
                 if (ret != 0) {
commit 7a65c8cc315c76bde6d692845c12e7ba06f44f89
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Feb 9 06:11:16 2012 +0000

    ARM devboards: Set arm_sysctl properties before init, not after
    
    The ARM devboard models (vexpress-a9, realview, versatilepb, etc)
    were accidentally trying to set one of the arm_sysctl properties
    after device init. This has now become a fatal error; set the property
    before device init where it should be done instead.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/realview.c b/hw/realview.c
index 821e627..8b0b03d 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -217,8 +217,8 @@ static void realview_init(ram_addr_t ram_size,
     sys_id = is_pb ? 0x01780500 : 0xc1400400;
     sysctl = qdev_create(NULL, "realview_sysctl");
     qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
-    qdev_init_nofail(sysctl);
     qdev_prop_set_uint32(sysctl, "proc_id", proc_id);
+    qdev_init_nofail(sysctl);
     sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000);
 
     if (is_mpcore) {
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 6e28e78..6ea0ce5 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -198,8 +198,8 @@ static void versatile_init(ram_addr_t ram_size,
 
     sysctl = qdev_create(NULL, "realview_sysctl");
     qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004);
-    qdev_init_nofail(sysctl);
     qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000);
+    qdev_init_nofail(sysctl);
     sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000);
 
     cpu_pic = arm_pic_init_cpu(env);
diff --git a/hw/vexpress.c b/hw/vexpress.c
index 64fab45..43f47a6 100644
--- a/hw/vexpress.c
+++ b/hw/vexpress.c
@@ -123,8 +123,8 @@ static void vexpress_a9_init(ram_addr_t ram_size,
     /* 0x10000000 System registers */
     sysctl = qdev_create(NULL, "realview_sysctl");
     qdev_prop_set_uint32(sysctl, "sys_id", sys_id);
-    qdev_init_nofail(sysctl);
     qdev_prop_set_uint32(sysctl, "proc_id", proc_id);
+    qdev_init_nofail(sysctl);
     sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000);
 
     /* 0x10001000 SP810 system control */
commit a4aecd2819fd31641ab62472e3385073043521fb
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sun Feb 5 12:45:20 2012 +0100

    apic: Fix legacy vmstate loading for KVM
    
    Also in case of loading pre-vmstate machines, we also need to open-code
    the reading of the timer expires value and instead call the post_load
    callback to apply it (or not). This fixes loading of legacy states into
    the KVM APIC.
    
    Reported-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>

diff --git a/hw/apic_common.c b/hw/apic_common.c
index 26991b4..8373d79 100644
--- a/hw/apic_common.c
+++ b/hw/apic_common.c
@@ -188,6 +188,7 @@ static void apic_reset_common(DeviceState *d)
 static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
 {
     APICCommonState *s = opaque;
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
     int i;
 
     if (version_id > 2) {
@@ -220,7 +221,11 @@ static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
     s->next_time = qemu_get_be64(f);
 
     if (version_id >= 2) {
-        qemu_get_timer(f, s->timer);
+        s->timer_expiry = qemu_get_be64(f);
+    }
+
+    if (info->post_load) {
+        info->post_load(s);
     }
     return 0;
 }
commit 3d4b26494fdce89354dac49ef909356ccda77914
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Jan 31 19:17:52 2012 +0100

    kvm: Implement kvm_irqchip_in_kernel like kvm_enabled
    
    To both avoid that kvm_irqchip_in_kernel always has to be paired with
    kvm_enabled and that the former ends up in a function call, implement it
    like the latter. This means keeping the state in a global variable and
    defining kvm_irqchip_in_kernel as a preprocessor macro.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>

diff --git a/hw/pc.c b/hw/pc.c
index 7f3aa65..3b35735 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -889,7 +889,7 @@ static DeviceState *apic_init(void *env, uint8_t apic_id)
     DeviceState *dev;
     static int apic_mapped;
 
-    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+    if (kvm_irqchip_in_kernel()) {
         dev = qdev_create(NULL, "kvm-apic");
     } else {
         dev = qdev_create(NULL, "apic");
@@ -908,7 +908,7 @@ static DeviceState *apic_init(void *env, uint8_t apic_id)
     }
 
     /* KVM does not support MSI yet. */
-    if (!kvm_enabled() || !kvm_irqchip_in_kernel()) {
+    if (!kvm_irqchip_in_kernel()) {
         msi_supported = true;
     }
 
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index c06f1b5..17f8d5d 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -104,7 +104,7 @@ static void ioapic_init(GSIState *gsi_state)
     SysBusDevice *d;
     unsigned int i;
 
-    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+    if (kvm_irqchip_in_kernel()) {
         dev = qdev_create(NULL, "kvm-ioapic");
     } else {
         dev = qdev_create(NULL, "ioapic");
@@ -183,7 +183,7 @@ static void pc_init1(MemoryRegion *system_memory,
     }
 
     gsi_state = g_malloc0(sizeof(*gsi_state));
-    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+    if (kvm_irqchip_in_kernel()) {
         kvm_piix3_setup_irq_routing(pci_enabled);
         gsi = qemu_allocate_irqs(kvm_piix3_gsi_handler, gsi_state,
                                  GSI_NUM_PINS);
@@ -209,7 +209,7 @@ static void pc_init1(MemoryRegion *system_memory,
     }
     isa_bus_irqs(isa_bus, gsi);
 
-    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+    if (kvm_irqchip_in_kernel()) {
         i8259 = kvm_i8259_init(isa_bus);
     } else if (xen_enabled()) {
         i8259 = xen_interrupt_controller_init();
diff --git a/kvm-all.c b/kvm-all.c
index 0b87658..c4babda 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -74,7 +74,6 @@ struct KVMState
 #ifdef KVM_CAP_SET_GUEST_DEBUG
     struct kvm_sw_breakpoint_head kvm_sw_breakpoints;
 #endif
-    int irqchip_in_kernel;
     int pit_in_kernel;
     int xsave, xcrs;
     int many_ioeventfds;
@@ -88,6 +87,7 @@ struct KVMState
 };
 
 KVMState *kvm_state;
+bool kvm_kernel_irqchip;
 
 static const KVMCapabilityInfo kvm_required_capabilites[] = {
     KVM_CAP_INFO(USER_MEMORY),
@@ -193,11 +193,6 @@ static void kvm_reset_vcpu(void *opaque)
     kvm_arch_reset_vcpu(env);
 }
 
-int kvm_irqchip_in_kernel(void)
-{
-    return kvm_state->irqchip_in_kernel;
-}
-
 int kvm_pit_in_kernel(void)
 {
     return kvm_state->pit_in_kernel;
@@ -742,7 +737,7 @@ int kvm_irqchip_set_irq(KVMState *s, int irq, int level)
     struct kvm_irq_level event;
     int ret;
 
-    assert(s->irqchip_in_kernel);
+    assert(kvm_irqchip_in_kernel());
 
     event.level = level;
     event.irq = irq;
@@ -862,7 +857,7 @@ static int kvm_irqchip_create(KVMState *s)
     if (kvm_check_extension(s, KVM_CAP_IRQ_INJECT_STATUS)) {
         s->irqchip_inject_ioctl = KVM_IRQ_LINE_STATUS;
     }
-    s->irqchip_in_kernel = 1;
+    kvm_kernel_irqchip = true;
 
     kvm_init_irq_routing(s);
 
@@ -1315,7 +1310,7 @@ int kvm_has_gsi_routing(void)
 
 int kvm_allows_irq0_override(void)
 {
-    return !kvm_enabled() || !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
+    return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
 }
 
 void kvm_setup_guest_memory(void *start, size_t size)
diff --git a/kvm-stub.c b/kvm-stub.c
index 6c2b06b..f63a0d2 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -16,11 +16,6 @@
 #include "gdbstub.h"
 #include "kvm.h"
 
-int kvm_irqchip_in_kernel(void)
-{
-    return 0;
-}
-
 int kvm_pit_in_kernel(void)
 {
     return 0;
diff --git a/kvm.h b/kvm.h
index 40b5ffc..f9f1dc8 100644
--- a/kvm.h
+++ b/kvm.h
@@ -23,11 +23,14 @@
 #endif
 
 extern int kvm_allowed;
+extern bool kvm_kernel_irqchip;
 
 #if defined CONFIG_KVM || !defined NEED_CPU_H
-#define kvm_enabled() (kvm_allowed)
+#define kvm_enabled()           (kvm_allowed)
+#define kvm_irqchip_in_kernel() (kvm_kernel_irqchip)
 #else
-#define kvm_enabled() (0)
+#define kvm_enabled()           (0)
+#define kvm_irqchip_in_kernel() (false)
 #endif
 
 struct kvm_run;
@@ -80,7 +83,6 @@ int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset);
 #endif
 
 int kvm_pit_in_kernel(void);
-int kvm_irqchip_in_kernel(void);
 
 int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr);
 int kvm_on_sigbus(int code, void *addr);
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 445c060..981192d 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -1356,7 +1356,7 @@ static int kvm_get_apic(CPUState *env)
     struct kvm_lapic_state kapic;
     int ret;
 
-    if (apic && kvm_enabled() && kvm_irqchip_in_kernel()) {
+    if (apic && kvm_irqchip_in_kernel()) {
         ret = kvm_vcpu_ioctl(env, KVM_GET_LAPIC, &kapic);
         if (ret < 0) {
             return ret;
@@ -1372,7 +1372,7 @@ static int kvm_put_apic(CPUState *env)
     DeviceState *apic = env->apic_state;
     struct kvm_lapic_state kapic;
 
-    if (apic && kvm_enabled() && kvm_irqchip_in_kernel()) {
+    if (apic && kvm_irqchip_in_kernel()) {
         kvm_put_apic_state(apic, &kapic);
 
         return kvm_vcpu_ioctl(env, KVM_SET_LAPIC, &kapic);
commit 39d6960aabfd90bf0bf7ba38d69e918962b70b16
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Wed Jan 25 18:14:15 2012 +0100

    kvm: Allow to set shadow MMU size
    
    Introduce the KVM-specific machine option kvm_shadow_mem. It allows to
    set a custom shadow MMU size for the virtual machine. This is useful for
    stress testing e.g.
    
    Only x86 supports this for now, but it is in principle a generic
    concept for all targets with shadow MMUs.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>

diff --git a/qemu-config.c b/qemu-config.c
index b030205..95bf5e5 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -535,6 +535,10 @@ static QemuOptsList qemu_machine_opts = {
             .name = "kernel_irqchip",
             .type = QEMU_OPT_BOOL,
             .help = "use KVM in-kernel irqchip",
+        }, {
+            .name = "kvm_shadow_mem",
+            .type = QEMU_OPT_SIZE,
+            .help = "KVM shadow MMU size",
         },
         { /* End of list */ }
     },
diff --git a/qemu-options.hx b/qemu-options.hx
index 19906e5..4ad1fc7 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -32,7 +32,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
     "                selects emulated machine (-machine ? for list)\n"
     "                property accel=accel1[:accel2[:...]] selects accelerator\n"
     "                supported accelerators are kvm, xen, tcg (default: tcg)\n"
-    "                kernel_irqchip=on|off controls accelerated irqchip support\n",
+    "                kernel_irqchip=on|off controls accelerated irqchip support\n"
+    "                kvm_shadow_mem=size of KVM shadow MMU\n",
     QEMU_ARCH_ALL)
 STEXI
 @item -machine [type=]@var{name}[,prop=@var{value}[,...]]
@@ -47,6 +48,8 @@ than one accelerator specified, the next one is used if the previous one fails
 to initialize.
 @item kernel_irqchip=on|off
 Enables in-kernel irqchip support for the chosen accelerator when available.
+ at item kvm_shadow_mem=size
+Defines the size of the KVM shadow MMU.
 @end table
 ETEXI
 
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index e41de39..445c060 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -646,7 +646,9 @@ static int kvm_get_supported_msrs(KVMState *s)
 
 int kvm_arch_init(KVMState *s)
 {
+    QemuOptsList *list = qemu_find_opts("machine");
     uint64_t identity_base = 0xfffbc000;
+    uint64_t shadow_mem;
     int ret;
     struct utsname utsname;
 
@@ -693,6 +695,17 @@ int kvm_arch_init(KVMState *s)
     }
     qemu_register_reset(kvm_unpoison_all, NULL);
 
+    if (!QTAILQ_EMPTY(&list->head)) {
+        shadow_mem = qemu_opt_get_size(QTAILQ_FIRST(&list->head),
+                                       "kvm_shadow_mem", -1);
+        if (shadow_mem != -1) {
+            shadow_mem /= 4096;
+            ret = kvm_vm_ioctl(s, KVM_SET_NR_MMU_PAGES, shadow_mem);
+            if (ret < 0) {
+                return ret;
+            }
+        }
+    }
     return 0;
 }
 
commit a642153013b2d0af106c0d4b9a637677d1e2c010
Merge: dc717bf... a3d4a1b...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 8 07:24:37 2012 -0600

    Merge remote-tracking branch 'bonzini/qdev-props-for-anthony' into staging
    
    * bonzini/qdev-props-for-anthony: (25 commits)
      qdev: remove unused fields from PropertyInfo
      qdev: initialize properties via QOM
      qdev: inline qdev_prop_set into qdev_prop_set_ptr
      qdev: access properties via QOM
      qdev: fix off-by-one
      qdev: let QOM free properties
      qdev: remove parse/print methods for pointer properties
      qdev: make the non-legacy pci address property accept an integer
      qdev: remove parse/print methods for mac properties
      qdev: remove print/parse methods from LostTickPolicy properties
      qdev: remove parse method for string properties
      qdev: allow reusing get/set for legacy property
      qdev: remove direct calls to print/parse
      qom: add property get/set wrappers for links
      qom: fix canonical paths vs. interfaces
      qom: use object_resolve_path_type for links
      qom: add object_resolve_path_type
      qom: fix off-by-one
      qom: add property get/set wrappers for C types
      qom: add QObject-based property get/set wrappers
      ...

commit dc717bfd057ac3d6b75c633d57e501d5e6d5ef50
Merge: a283b1b... eed9686...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 8 07:23:55 2012 -0600

    Merge remote-tracking branch 'aneesh/for-upstream' into staging
    
    * aneesh/for-upstream:
      hw/9pfs: Remove O_NOATIME flag from 9pfs open() calls in readonly mode
      hw/9pfs: Update MAINTAINERS file
      fsdev: Fix parameter parsing for proxy helper
      hw/9pfs: Fix crash when mounting with synthfs
      hw/9pfs: Preserve S_ISGID
      hw/9pfs: Add new security model mapped-file.

commit a283b1b8eb121dcc086c4850c91b35fed13d2023
Merge: cf4dc46... edc1de9...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 8 07:23:23 2012 -0600

    Merge remote-tracking branch 'sweil/w32' into staging
    
    * sweil/w32:
      w32: Initialise critical section before starting thread (fix #922131)
      w32: Build windows and console executables

commit 6612db12d56c68fff3e56ca4ea8c41d9d55c12e4
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Wed Feb 8 10:05:45 2012 +0100

    slirp: Prevent sending ICMP error replies to source-only addresses
    
    This triggered the related assert in arp_table_search.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c
index 4b43994..5dbf21d 100644
--- a/slirp/ip_icmp.c
+++ b/slirp/ip_icmp.c
@@ -262,6 +262,11 @@ icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
 #endif
   if(ip->ip_off & IP_OFFMASK) goto end_error;    /* Only reply to fragment 0 */
 
+  /* Do not reply to source-only IPs */
+  if ((ip->ip_src.s_addr & htonl(~(0xf << 28))) == 0) {
+      goto end_error;
+  }
+
   shlen=ip->ip_hl << 2;
   s_ip_len=ip->ip_len;
   if(ip->ip_p == IPPROTO_ICMP) {
commit 9f1134d4aac64ea427453fc7c7f8cab39f4fe3da
Author: Stefan Weil <sw at weilnetz.de>
Date:   Thu Jan 5 14:18:45 2012 +0100

    slirp: Remove unused variable and unused code
    
    9634d9031c140b24c7ca0d8872632207f6ce7275 disabled unused code.
    This patch removes what was left.
    
    If do_pty is 2, the function returns immediately, so any later checks
    for do_pty == 2 will always fail and can be removed together with
    the code which is never executed. Then variable master is unused and
    can be removed, too.
    
    This issue was detected by coverity.
    
    Cc: Blue Swirl <blauwirbel at gmail.com>
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/slirp/misc.c b/slirp/misc.c
index 6c80e69..3432fbf 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -113,7 +113,6 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
 	struct sockaddr_in addr;
 	socklen_t addrlen = sizeof(addr);
 	int opt;
-        int master = -1;
 	const char *argv[256];
 	/* don't want to clobber the original */
 	char *bptr;
@@ -148,32 +147,23 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
 	 case -1:
 		lprint("Error: fork failed: %s\n", strerror(errno));
 		close(s);
-		if (do_pty == 2)
-		   close(master);
 		return 0;
 
 	 case 0:
                 setsid();
 
 		/* Set the DISPLAY */
-		if (do_pty == 2) {
-			(void) close(master);
-#ifdef TIOCSCTTY /* XXXXX */
-			ioctl(s, TIOCSCTTY, (char *)NULL);
-#endif
-		} else {
-			getsockname(s, (struct sockaddr *)&addr, &addrlen);
-			close(s);
-			/*
-			 * Connect to the socket
-			 * XXX If any of these fail, we're in trouble!
-	 		 */
-			s = qemu_socket(AF_INET, SOCK_STREAM, 0);
-			addr.sin_addr = loopback_addr;
-                        do {
-                            ret = connect(s, (struct sockaddr *)&addr, addrlen);
-                        } while (ret < 0 && errno == EINTR);
-		}
+                getsockname(s, (struct sockaddr *)&addr, &addrlen);
+                close(s);
+                /*
+                 * Connect to the socket
+                 * XXX If any of these fail, we're in trouble!
+                 */
+                s = qemu_socket(AF_INET, SOCK_STREAM, 0);
+                addr.sin_addr = loopback_addr;
+                do {
+                    ret = connect(s, (struct sockaddr *)&addr, addrlen);
+                } while (ret < 0 && errno == EINTR);
 
 		dup2(s, 0);
 		dup2(s, 1);
@@ -210,26 +200,21 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
 
 	 default:
 		qemu_add_child_watch(pid);
-		if (do_pty == 2) {
-			close(s);
-			so->s = master;
-		} else {
-			/*
-			 * XXX this could block us...
-			 * XXX Should set a timer here, and if accept() doesn't
-		 	 * return after X seconds, declare it a failure
-		 	 * The only reason this will block forever is if socket()
-		 	 * of connect() fail in the child process
-		 	 */
-                        do {
-                            so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
-                        } while (so->s < 0 && errno == EINTR);
-                        closesocket(s);
-			opt = 1;
-			setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
-			opt = 1;
-			setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
-		}
+                /*
+                 * XXX this could block us...
+                 * XXX Should set a timer here, and if accept() doesn't
+                 * return after X seconds, declare it a failure
+                 * The only reason this will block forever is if socket()
+                 * of connect() fail in the child process
+                 */
+                do {
+                    so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
+                } while (so->s < 0 && errno == EINTR);
+                closesocket(s);
+                opt = 1;
+                setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int));
+                opt = 1;
+                setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, (char *)&opt, sizeof(int));
 		fd_nonblock(so->s);
 
 		/* Append the telnet options now */
commit cf4dc461a4cfc3e056ee24edb26154f4d34a6278
Author: malc <av1474 at comtv.ru>
Date:   Tue Feb 7 22:11:04 2012 +0400

    Restore consistent formatting
    
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/hw/ac97.c b/hw/ac97.c
index ed2e4cd..7bf9171 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 = {
@@ -1345,14 +1345,14 @@ int ac97_init (PCIBus *bus)
 }
 
 static Property ac97_properties[] = {
-    DEFINE_PROP_UINT32("use_broken_id", AC97LinkState, use_broken_id, 0),
-    DEFINE_PROP_END_OF_LIST(),
+    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)
+static void ac97_class_init (ObjectClass *klass, void *data)
 {
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS (klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
 
     k->init = ac97_initfn;
     k->exit = ac97_exitfn;
@@ -1374,7 +1374,7 @@ static TypeInfo ac97_info = {
 
 static void ac97_register (void)
 {
-    type_register_static(&ac97_info);
+    type_register_static (&ac97_info);
 }
 device_init (ac97_register);
 
diff --git a/hw/adlib.c b/hw/adlib.c
index dd8b188..d39cd97 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/cs4231a.c b/hw/cs4231a.c
index 811dda6..ad04ad6 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 ()
     }
 };
 
@@ -672,10 +672,10 @@ static Property cs4231a_properties[] = {
     DEFINE_PROP_END_OF_LIST (),
 };
 
-static void cs4231a_class_initfn(ObjectClass *klass, void *data)
+static void cs4231a_class_initfn (ObjectClass *klass, void *data)
 {
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS (klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS (klass);
     ic->init = cs4231a_initfn;
     dc->desc = "Crystal Semiconductor CS4231A";
     dc->vmsd = &vmstate_cs4231a;
@@ -691,6 +691,6 @@ static TypeInfo cs4231a_info = {
 
 static void cs4231a_register (void)
 {
-    type_register_static(&cs4231a_info);
+    type_register_static (&cs4231a_info);
 }
 device_init (cs4231a_register)
diff --git a/hw/es1370.c b/hw/es1370.c
index 95e88b9..e377c48 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,10 +1031,10 @@ int es1370_init (PCIBus *bus)
     return 0;
 }
 
-static void es1370_class_init(ObjectClass *klass, void *data)
+static void es1370_class_init (ObjectClass *klass, void *data)
 {
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS (klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
 
     k->init = es1370_initfn;
     k->exit = es1370_exitfn;
@@ -1056,7 +1056,7 @@ static TypeInfo es1370_info = {
 
 static void es1370_register (void)
 {
-    type_register_static(&es1370_info);
+    type_register_static (&es1370_info);
 }
 device_init (es1370_register);
 
diff --git a/hw/gus.c b/hw/gus.c
index 49e5dbf..2054707 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)
@@ -307,10 +307,10 @@ static Property gus_properties[] = {
     DEFINE_PROP_END_OF_LIST (),
 };
 
-static void gus_class_initfn(ObjectClass *klass, void *data)
+static void gus_class_initfn (ObjectClass *klass, void *data)
 {
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS (klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS (klass);
     ic->init = gus_initfn;
     dc->desc = "Gravis Ultrasound GF1";
     dc->vmsd = &vmstate_gus;
@@ -326,6 +326,6 @@ static TypeInfo gus_info = {
 
 static void gus_register (void)
 {
-    type_register_static(&gus_info);
+    type_register_static (&gus_info);
 }
 device_init (gus_register)
diff --git a/hw/sb16.c b/hw/sb16.c
index ae25450..db8929b 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 (),
 };
 
 
@@ -1400,10 +1400,10 @@ static Property sb16_properties[] = {
     DEFINE_PROP_END_OF_LIST (),
 };
 
-static void sb16_class_initfn(ObjectClass *klass, void *data)
+static void sb16_class_initfn (ObjectClass *klass, void *data)
 {
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    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;
@@ -1419,6 +1419,6 @@ static TypeInfo sb16_info = {
 
 static void sb16_register (void)
 {
-    type_register_static(&sb16_info);
+    type_register_static (&sb16_info);
 }
 device_init (sb16_register)
commit edc1de97138af028bba216ef71d1d995834829df
Author: Stefan Weil <sw at weilnetz.de>
Date:   Tue Jan 31 07:14:15 2012 +0100

    w32: Initialise critical section before starting thread (fix #922131)
    
    This patch was contributed by Bogdan Harjoc. I added some assertions.
    
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Stefan Weil <sw at weilnetz.de>

diff --git a/qemu-thread-win32.c b/qemu-thread-win32.c
index fe9b931..3524c8b 100644
--- a/qemu-thread-win32.c
+++ b/qemu-thread-win32.c
@@ -215,8 +215,6 @@ static unsigned __stdcall win32_start_routine(void *arg)
     if (data->mode == QEMU_THREAD_DETACHED) {
         g_free(data);
         data = NULL;
-    } else {
-        InitializeCriticalSection(&data->cs);
     }
     TlsSetValue(qemu_thread_tls_index, data);
     qemu_thread_exit(start_routine(thread_arg));
@@ -227,6 +225,7 @@ void qemu_thread_exit(void *arg)
 {
     QemuThreadData *data = TlsGetValue(qemu_thread_tls_index);
     if (data) {
+        assert(data->mode != QEMU_THREAD_DETACHED);
         data->ret = arg;
         EnterCriticalSection(&data->cs);
         data->exited = true;
@@ -258,6 +257,7 @@ void *qemu_thread_join(QemuThread *thread)
         CloseHandle(handle);
     }
     ret = data->ret;
+    assert(data->mode != QEMU_THREAD_DETACHED);
     DeleteCriticalSection(&data->cs);
     g_free(data);
     return ret;
@@ -288,6 +288,10 @@ void qemu_thread_create(QemuThread *thread,
     data->mode = mode;
     data->exited = false;
 
+    if (data->mode != QEMU_THREAD_DETACHED) {
+        InitializeCriticalSection(&data->cs);
+    }
+
     hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine,
                                       data, 0, &thread->tid);
     if (!hThread) {
@@ -314,6 +318,7 @@ HANDLE qemu_thread_get_handle(QemuThread *thread)
         return NULL;
     }
 
+    assert(data->mode != QEMU_THREAD_DETACHED);
     EnterCriticalSection(&data->cs);
     if (!data->exited) {
         handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME, FALSE,
commit 0fa5491eed8ff4fe63cb63c93ce37ff76de7c010
Author: Stefan Weil <sw at weilnetz.de>
Date:   Thu Dec 22 11:18:53 2011 +0100

    w32: Build windows and console executables
    
    System emulation executables with SDL are typically windows
    executables. Sometimes console executables are more useful,
    so create both variants if linker option -mwindows was detected.
    
    v2:
    This version uses QEMU_PROGW / QEMU_PROG instead of QEMU_PROG / QEMU_PROGC.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>

diff --git a/Makefile.target b/Makefile.target
index 68481a3..7ed4979 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -29,10 +29,17 @@ ifdef CONFIG_USER_ONLY
 QEMU_PROG=qemu-$(TARGET_ARCH2)
 else
 # system emulator name
+ifneq (,$(findstring -mwindows,$(LIBS)))
+# Terminate program name with a 'w' because the linker builds a windows executable.
+QEMU_PROGW=qemu-system-$(TARGET_ARCH2)w$(EXESUF)
+endif # windows executable
 QEMU_PROG=qemu-system-$(TARGET_ARCH2)$(EXESUF)
 endif
 
 PROGS=$(QEMU_PROG)
+ifdef QEMU_PROGW
+PROGS+=$(QEMU_PROGW)
+endif
 STPFILES=
 
 ifndef CONFIG_HAIKU
@@ -407,9 +414,16 @@ endif # CONFIG_LINUX_USER
 
 obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
 
+ifdef QEMU_PROGW
+# The linker builds a windows executable. Make also a console executable.
+$(QEMU_PROGW): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
+	$(call LINK,$^)
+$(QEMU_PROG): $(QEMU_PROGW)
+	$(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG),"  GEN   $(TARGET_DIR)$(QEMU_PROG)")
+else
 $(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
 	$(call LINK,$^)
-
+endif
 
 gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
 	$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES),"  GEN   $(TARGET_DIR)$@")
commit a3d4a1b0479414fc4d59368a0635640979a9e4d2
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Feb 2 22:51:09 2012 +0100

    qdev: remove unused fields from PropertyInfo
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c
index 8daa733..0bb16c7 100644
--- a/hw/qdev-addr.c
+++ b/hw/qdev-addr.c
@@ -61,8 +61,6 @@ static void set_taddr(Object *obj, Visitor *v, void *opaque,
 
 PropertyInfo qdev_prop_taddr = {
     .name  = "taddr",
-    .type  = PROP_TYPE_TADDR,
-    .size  = sizeof(target_phys_addr_t),
     .parse = parse_taddr,
     .print = print_taddr,
     .get   = get_taddr,
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 49bed30..b6d6fcf 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -12,7 +12,7 @@ void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
 
 static uint32_t qdev_get_prop_mask(Property *prop)
 {
-    assert(prop->info->type == PROP_TYPE_BIT);
+    assert(prop->info == &qdev_prop_bit);
     return 0x1 << prop->bitnr;
 }
 
@@ -79,8 +79,6 @@ static void set_bit(Object *obj, Visitor *v, void *opaque,
 PropertyInfo qdev_prop_bit = {
     .name  = "boolean",
     .legacy_name  = "on/off",
-    .type  = PROP_TYPE_BIT,
-    .size  = sizeof(uint32_t),
     .parse = parse_bit,
     .print = print_bit,
     .get   = get_bit,
@@ -151,8 +149,6 @@ static void set_int8(Object *obj, Visitor *v, void *opaque,
 
 PropertyInfo qdev_prop_uint8 = {
     .name  = "uint8",
-    .type  = PROP_TYPE_UINT8,
-    .size  = sizeof(uint8_t),
     .parse = parse_uint8,
     .print = print_uint8,
     .get   = get_int8,
@@ -185,8 +181,6 @@ static int print_hex8(DeviceState *dev, Property *prop, char *dest, size_t len)
 PropertyInfo qdev_prop_hex8 = {
     .name  = "uint8",
     .legacy_name  = "hex8",
-    .type  = PROP_TYPE_UINT8,
-    .size  = sizeof(uint8_t),
     .parse = parse_hex8,
     .print = print_hex8,
     .get   = get_int8,
@@ -259,8 +253,6 @@ static void set_int16(Object *obj, Visitor *v, void *opaque,
 
 PropertyInfo qdev_prop_uint16 = {
     .name  = "uint16",
-    .type  = PROP_TYPE_UINT16,
-    .size  = sizeof(uint16_t),
     .parse = parse_uint16,
     .print = print_uint16,
     .get   = get_int16,
@@ -333,8 +325,6 @@ static void set_int32(Object *obj, Visitor *v, void *opaque,
 
 PropertyInfo qdev_prop_uint32 = {
     .name  = "uint32",
-    .type  = PROP_TYPE_UINT32,
-    .size  = sizeof(uint32_t),
     .parse = parse_uint32,
     .print = print_uint32,
     .get   = get_int32,
@@ -364,8 +354,6 @@ static int print_int32(DeviceState *dev, Property *prop, char *dest, size_t len)
 
 PropertyInfo qdev_prop_int32 = {
     .name  = "int32",
-    .type  = PROP_TYPE_INT32,
-    .size  = sizeof(int32_t),
     .parse = parse_int32,
     .print = print_int32,
     .get   = get_int32,
@@ -398,8 +386,6 @@ static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len)
 PropertyInfo qdev_prop_hex32 = {
     .name  = "uint32",
     .legacy_name  = "hex32",
-    .type  = PROP_TYPE_UINT32,
-    .size  = sizeof(uint32_t),
     .parse = parse_hex32,
     .print = print_hex32,
     .get   = get_int32,
@@ -457,8 +443,6 @@ static void set_int64(Object *obj, Visitor *v, void *opaque,
 
 PropertyInfo qdev_prop_uint64 = {
     .name  = "uint64",
-    .type  = PROP_TYPE_UINT64,
-    .size  = sizeof(uint64_t),
     .parse = parse_uint64,
     .print = print_uint64,
     .get   = get_int64,
@@ -489,8 +473,6 @@ static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len)
 PropertyInfo qdev_prop_hex64 = {
     .name  = "uint64",
     .legacy_name  = "hex64",
-    .type  = PROP_TYPE_UINT64,
-    .size  = sizeof(uint64_t),
     .parse = parse_hex64,
     .print = print_hex64,
     .get   = get_int64,
@@ -559,8 +541,6 @@ static void set_string(Object *obj, Visitor *v, void *opaque,
 
 PropertyInfo qdev_prop_string = {
     .name  = "string",
-    .type  = PROP_TYPE_STRING,
-    .size  = sizeof(char*),
     .print = print_string,
     .release = release_string,
     .get   = get_string,
@@ -655,8 +635,6 @@ static void set_drive(Object *obj, Visitor *v, void *opaque,
 
 PropertyInfo qdev_prop_drive = {
     .name  = "drive",
-    .type  = PROP_TYPE_DRIVE,
-    .size  = sizeof(BlockDriverState *),
     .get   = get_drive,
     .set   = set_drive,
     .release = release_drive,
@@ -711,8 +689,6 @@ static void set_chr(Object *obj, Visitor *v, void *opaque,
 
 PropertyInfo qdev_prop_chr = {
     .name  = "chr",
-    .type  = PROP_TYPE_CHR,
-    .size  = sizeof(CharDriverState*),
     .get   = get_chr,
     .set   = set_chr,
     .release = release_chr,
@@ -755,8 +731,6 @@ static void set_netdev(Object *obj, Visitor *v, void *opaque,
 
 PropertyInfo qdev_prop_netdev = {
     .name  = "netdev",
-    .type  = PROP_TYPE_NETDEV,
-    .size  = sizeof(VLANClientState*),
     .get   = get_netdev,
     .set   = set_netdev,
 };
@@ -834,8 +808,6 @@ static void set_vlan(Object *obj, Visitor *v, void *opaque,
 
 PropertyInfo qdev_prop_vlan = {
     .name  = "vlan",
-    .type  = PROP_TYPE_VLAN,
-    .size  = sizeof(VLANClientState*),
     .parse = parse_vlan,
     .print = print_vlan,
     .get   = get_vlan,
@@ -847,8 +819,6 @@ PropertyInfo qdev_prop_vlan = {
 /* Not a proper property, just for dirty hacks.  TODO Remove it!  */
 PropertyInfo qdev_prop_ptr = {
     .name  = "ptr",
-    .type  = PROP_TYPE_PTR,
-    .size  = sizeof(void*),
 };
 
 /* --- mac address --- */
@@ -917,8 +887,6 @@ inval:
 
 PropertyInfo qdev_prop_macaddr = {
     .name  = "macaddr",
-    .type  = PROP_TYPE_MACADDR,
-    .size  = sizeof(MACAddr),
     .get   = get_mac,
     .set   = set_mac,
 };
@@ -965,8 +933,6 @@ static void set_enum(Object *obj, Visitor *v, void *opaque,
 
 PropertyInfo qdev_prop_losttickpolicy = {
     .name  = "LostTickPolicy",
-    .type  = PROP_TYPE_LOSTTICKPOLICY,
-    .size  = sizeof(LostTickPolicy),
     .enum_table  = lost_tick_policy_table,
     .get   = get_enum,
     .set   = set_enum,
@@ -1012,8 +978,6 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t
 PropertyInfo qdev_prop_pci_devfn = {
     .name  = "int32",
     .legacy_name  = "pci-devfn",
-    .type  = PROP_TYPE_UINT32,
-    .size  = sizeof(uint32_t),
     .parse = parse_pci_devfn,
     .print = print_pci_devfn,
     .get   = get_int32,
diff --git a/hw/qdev.h b/hw/qdev.h
index a3bcf0b..9cc3f98 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -117,30 +117,9 @@ struct Property {
     int64_t      defval;
 };
 
-enum PropertyType {
-    PROP_TYPE_UNSPEC = 0,
-    PROP_TYPE_UINT8,
-    PROP_TYPE_UINT16,
-    PROP_TYPE_UINT32,
-    PROP_TYPE_INT32,
-    PROP_TYPE_UINT64,
-    PROP_TYPE_TADDR,
-    PROP_TYPE_MACADDR,
-    PROP_TYPE_LOSTTICKPOLICY,
-    PROP_TYPE_DRIVE,
-    PROP_TYPE_CHR,
-    PROP_TYPE_STRING,
-    PROP_TYPE_NETDEV,
-    PROP_TYPE_VLAN,
-    PROP_TYPE_PTR,
-    PROP_TYPE_BIT,
-};
-
 struct PropertyInfo {
     const char *name;
     const char *legacy_name;
-    size_t size;
-    enum PropertyType type;
     const char **enum_table;
     int64_t min;
     int64_t max;
commit 4f2d3d705c1ae7dce29254e2c4645c84e77a74d4
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Feb 2 09:43:02 2012 +0100

    qdev: initialize properties via QOM
    
    Similarly, use the object properties also to set the default
    values of the qdev properties.  This requires reordering
    registration and initialization.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index b3cd2a8..49bed30 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -26,17 +26,6 @@ static void bit_prop_set(DeviceState *dev, Property *props, bool val)
         *p &= ~mask;
 }
 
-static void qdev_prop_cpy(DeviceState *dev, Property *props, void *src)
-{
-    if (props->info->type == PROP_TYPE_BIT) {
-        bool *defval = src;
-        bit_prop_set(dev, props, *defval);
-    } else {
-        char *dst = qdev_get_prop_ptr(dev, props);
-        memcpy(dst, src, props->info->size);
-    }
-}
-
 /* Bit */
 static int parse_bit(DeviceState *dev, Property *prop, const char *str)
 {
@@ -1241,13 +1230,23 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
 
 void qdev_prop_set_defaults(DeviceState *dev, Property *props)
 {
+    Object *obj = OBJECT(dev);
     if (!props)
         return;
-    while (props->name) {
-        if (props->defval) {
-            qdev_prop_cpy(dev, props, props->defval);
+    for (; props->name; props++) {
+        Error *errp = NULL;
+        if (props->qtype == QTYPE_NONE) {
+            continue;
         }
-        props++;
+        if (props->qtype == QTYPE_QBOOL) {
+            object_property_set_bool(obj, props->defval, props->name, &errp);
+        } else if (props->info->enum_table) {
+            object_property_set_str(obj, props->info->enum_table[props->defval],
+                                    props->name, &errp);
+        } else if (props->qtype == QTYPE_QINT) {
+            object_property_set_int(obj, props->defval, props->name, &errp);
+        }
+        assert(!errp);
     }
 }
 
diff --git a/hw/qdev.c b/hw/qdev.c
index 487ca5d..8a413ef 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -86,11 +86,11 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
     dev->parent_bus = bus;
     QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
 
-    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_prop_set_defaults(dev, dev->parent_bus->info->props);
 }
 
 /* Create a new device.  This only initializes the device state structure
@@ -612,13 +612,13 @@ static void device_initfn(Object *obj)
     dev->instance_id_alias = -1;
     dev->state = DEV_STATE_CREATED;
 
-    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);
     }
 
     object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL);
+    qdev_prop_set_defaults(dev, qdev_get_props(dev));
 }
 
 /* Unlink device from bus and free the structure.  */
diff --git a/hw/qdev.h b/hw/qdev.h
index 9ccd5c3..a3bcf0b 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -112,8 +112,9 @@ struct Property {
     const char   *name;
     PropertyInfo *info;
     int          offset;
-    int          bitnr;
-    void         *defval;
+    uint8_t      bitnr;
+    uint8_t      qtype;
+    int64_t      defval;
 };
 
 enum PropertyType {
@@ -255,7 +256,8 @@ extern PropertyInfo qdev_prop_pci_devfn;
         .info      = &(_prop),                                          \
         .offset    = offsetof(_state, _field)                           \
             + type_check(_type,typeof_field(_state, _field)),           \
-        .defval    = (_type[]) { _defval },                             \
+        .qtype     = QTYPE_QINT,                                        \
+        .defval    = (_type)_defval,                                    \
         }
 #define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) {  \
         .name      = (_name),                                    \
@@ -263,7 +265,8 @@ extern PropertyInfo qdev_prop_pci_devfn;
         .bitnr    = (_bit),                                      \
         .offset    = offsetof(_state, _field)                    \
             + type_check(uint32_t,typeof_field(_state, _field)), \
-        .defval    = (bool[]) { (_defval) },                     \
+        .qtype     = QTYPE_QBOOL,                                \
+        .defval    = (bool)_defval,                              \
         }
 
 #define DEFINE_PROP_UINT8(_n, _s, _f, _d)                       \
commit 7a7aae21ccab06606cee9aba846d2e30cb616763
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Feb 2 16:58:31 2012 +0100

    qdev: inline qdev_prop_set into qdev_prop_set_ptr
    
    qdev_prop_set is not needed anymore except for hacks, simplify it and
    inline it.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 5a11676..b3cd2a8 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -1115,24 +1115,6 @@ int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
     return 0;
 }
 
-static void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type)
-{
-    Property *prop;
-
-    prop = qdev_prop_find(dev, name);
-    if (!prop) {
-        fprintf(stderr, "%s: property \"%s.%s\" not found\n",
-                __FUNCTION__, object_get_typename(OBJECT(dev)), name);
-        abort();
-    }
-    if (prop->info->type != type) {
-        fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n",
-                __FUNCTION__, object_get_typename(OBJECT(dev)), name);
-        abort();
-    }
-    qdev_prop_cpy(dev, prop, src);
-}
-
 void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
 {
     Error *errp = NULL;
@@ -1248,7 +1230,13 @@ void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
 
 void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
 {
-    qdev_prop_set(dev, name, &value, PROP_TYPE_PTR);
+    Property *prop;
+    void **ptr;
+
+    prop = qdev_prop_find(dev, name);
+    assert(prop && prop->info == &qdev_prop_ptr);
+    ptr = qdev_get_prop_ptr(dev, prop);
+    *ptr = value;
 }
 
 void qdev_prop_set_defaults(DeviceState *dev, Property *props)
commit 9b170e60adc6dc01564128cf09f96ec923ed6526
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Feb 2 12:51:44 2012 +0100

    qdev: access properties via QOM
    
    Do not poke anymore in the struct when accessing qdev properties.
    Instead, ask the object to set the right value.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c
index 5976dcd..8daa733 100644
--- a/hw/qdev-addr.c
+++ b/hw/qdev-addr.c
@@ -71,5 +71,8 @@ PropertyInfo qdev_prop_taddr = {
 
 void qdev_prop_set_taddr(DeviceState *dev, const char *name, target_phys_addr_t value)
 {
-    qdev_prop_set(dev, name, &value, PROP_TYPE_TADDR);
+    Error *errp = NULL;
+    object_property_set_int(OBJECT(dev), value, name, &errp);
+    assert(!errp);
+
 }
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index debb37f..5a11676 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -1115,7 +1115,7 @@ int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
     return 0;
 }
 
-void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type)
+static void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type)
 {
     Property *prop;
 
@@ -1135,52 +1135,63 @@ void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyT
 
 void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
 {
-    qdev_prop_set(dev, name, &value, PROP_TYPE_BIT);
+    Error *errp = NULL;
+    object_property_set_bool(OBJECT(dev), value, name, &errp);
+    assert(!errp);
 }
 
 void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value)
 {
-    qdev_prop_set(dev, name, &value, PROP_TYPE_UINT8);
+    Error *errp = NULL;
+    object_property_set_int(OBJECT(dev), value, name, &errp);
+    assert(!errp);
 }
 
 void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value)
 {
-    qdev_prop_set(dev, name, &value, PROP_TYPE_UINT16);
+    Error *errp = NULL;
+    object_property_set_int(OBJECT(dev), value, name, &errp);
+    assert(!errp);
 }
 
 void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value)
 {
-    qdev_prop_set(dev, name, &value, PROP_TYPE_UINT32);
+    Error *errp = NULL;
+    object_property_set_int(OBJECT(dev), value, name, &errp);
+    assert(!errp);
 }
 
 void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value)
 {
-    qdev_prop_set(dev, name, &value, PROP_TYPE_INT32);
+    Error *errp = NULL;
+    object_property_set_int(OBJECT(dev), value, name, &errp);
+    assert(!errp);
 }
 
 void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value)
 {
-    qdev_prop_set(dev, name, &value, PROP_TYPE_UINT64);
+    Error *errp = NULL;
+    object_property_set_int(OBJECT(dev), value, name, &errp);
+    assert(!errp);
 }
 
 void qdev_prop_set_string(DeviceState *dev, const char *name, char *value)
 {
-    qdev_prop_set(dev, name, &value, PROP_TYPE_STRING);
+    Error *errp = NULL;
+    object_property_set_str(OBJECT(dev), value, name, &errp);
+    assert(!errp);
 }
 
 int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value)
 {
-    int res;
-
-    res = bdrv_attach_dev(value, dev);
-    if (res < 0) {
-        error_report("Can't attach drive %s to %s.%s: %s",
-                     bdrv_get_device_name(value),
-                     dev->id ? dev->id : object_get_typename(OBJECT(dev)),
-                     name, strerror(-res));
+    Error *errp = NULL;
+    object_property_set_str(OBJECT(dev), bdrv_get_device_name(value),
+                            name, &errp);
+    if (errp) {
+        qerror_report_err(errp);
+        error_free(errp);
         return -1;
     }
-    qdev_prop_set(dev, name, &value, PROP_TYPE_DRIVE);
     return 0;
 }
 
@@ -1192,28 +1203,47 @@ void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverS
 }
 void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value)
 {
-    qdev_prop_set(dev, name, &value, PROP_TYPE_CHR);
+    Error *errp = NULL;
+    assert(value->label);
+    object_property_set_str(OBJECT(dev), value->label, name, &errp);
+    assert(!errp);
 }
 
 void qdev_prop_set_netdev(DeviceState *dev, const char *name, VLANClientState *value)
 {
-    qdev_prop_set(dev, name, &value, PROP_TYPE_NETDEV);
+    Error *errp = NULL;
+    assert(value->name);
+    object_property_set_str(OBJECT(dev), value->name, name, &errp);
+    assert(!errp);
 }
 
 void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value)
 {
-    qdev_prop_set(dev, name, &value, PROP_TYPE_VLAN);
+    Error *errp = NULL;
+    object_property_set_int(OBJECT(dev), value ? value->id : -1, name, &errp);
+    assert(!errp);
 }
 
 void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
 {
-    qdev_prop_set(dev, name, value, PROP_TYPE_MACADDR);
+    Error *errp = NULL;
+    char str[2 * 6 + 5 + 1];
+    snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x",
+             value[0], value[1], value[2], value[3], value[4], value[5]);
+
+    object_property_set_str(OBJECT(dev), str, name, &errp);
+    assert(!errp);
 }
 
-void qdev_prop_set_losttickpolicy(DeviceState *dev, const char *name,
-                                  LostTickPolicy *value)
+void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
 {
-    qdev_prop_set(dev, name, value, PROP_TYPE_LOSTTICKPOLICY);
+    Property *prop;
+    Error *errp = NULL;
+
+    prop = qdev_prop_find(dev, name);
+    object_property_set_str(OBJECT(dev), prop->info->enum_table[value],
+                            name, &errp);
+    assert(!errp);
 }
 
 void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
diff --git a/hw/qdev.h b/hw/qdev.h
index acccf26..9ccd5c3 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -310,7 +310,6 @@ extern PropertyInfo qdev_prop_pci_devfn;
 void *qdev_get_prop_ptr(DeviceState *dev, Property *prop);
 int qdev_prop_exists(DeviceState *dev, const char *name);
 int qdev_prop_parse(DeviceState *dev, const char *name, const char *value);
-void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type);
 void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value);
 void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value);
 void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value);
@@ -324,8 +323,7 @@ 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);
+void qdev_prop_set_enum(DeviceState *dev, const char *name, int 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);
commit 6350b0904615cc0531cc3059ea34db5c009c88aa
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Feb 2 16:19:21 2012 +0100

    qdev: fix off-by-one
    
    Integer properties did not work.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index d69a987..debb37f 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -151,7 +151,7 @@ static void set_int8(Object *obj, Visitor *v, void *opaque,
         error_propagate(errp, local_err);
         return;
     }
-    if (value > prop->info->min && value <= prop->info->max) {
+    if (value >= prop->info->min && value <= prop->info->max) {
         *ptr = value;
     } else {
         error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
@@ -259,7 +259,7 @@ static void set_int16(Object *obj, Visitor *v, void *opaque,
         error_propagate(errp, local_err);
         return;
     }
-    if (value > prop->info->min && value <= prop->info->max) {
+    if (value >= prop->info->min && value <= prop->info->max) {
         *ptr = value;
     } else {
         error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
@@ -333,7 +333,7 @@ static void set_int32(Object *obj, Visitor *v, void *opaque,
         error_propagate(errp, local_err);
         return;
     }
-    if (value > prop->info->min && value <= prop->info->max) {
+    if (value >= prop->info->min && value <= prop->info->max) {
         *ptr = value;
     } else {
         error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
commit dd0ba250ca83ed915ea192ab7539cdbb4e868c14
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Feb 2 13:08:48 2012 +0100

    qdev: let QOM free properties
    
    Drop the special free callback.  Instead, register a "regular"
    release method in the non-legacy property.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 67995a3..d69a987 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -510,9 +510,10 @@ PropertyInfo qdev_prop_hex64 = {
 
 /* --- string --- */
 
-static void free_string(DeviceState *dev, Property *prop)
+static void release_string(Object *obj, const char *name, void *opaque)
 {
-    g_free(*(char **)qdev_get_prop_ptr(dev, prop));
+    Property *prop = opaque;
+    g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop));
 }
 
 static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len)
@@ -572,7 +573,7 @@ PropertyInfo qdev_prop_string = {
     .type  = PROP_TYPE_STRING,
     .size  = sizeof(char*),
     .print = print_string,
-    .free  = free_string,
+    .release = release_string,
     .get   = get_string,
     .set   = set_string,
 };
@@ -592,8 +593,10 @@ static int parse_drive(DeviceState *dev, const char *str, void **ptr)
     return 0;
 }
 
-static void free_drive(DeviceState *dev, Property *prop)
+static void release_drive(Object *obj, const char *name, void *opaque)
 {
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
     BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop);
 
     if (*ptr) {
@@ -667,7 +670,7 @@ PropertyInfo qdev_prop_drive = {
     .size  = sizeof(BlockDriverState *),
     .get   = get_drive,
     .set   = set_drive,
-    .free  = free_drive,
+    .release = release_drive,
 };
 
 /* --- character device --- */
@@ -686,8 +689,10 @@ static int parse_chr(DeviceState *dev, const char *str, void **ptr)
     return 0;
 }
 
-static void free_chr(DeviceState *dev, Property *prop)
+static void release_chr(Object *obj, const char *name, void *opaque)
 {
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
     CharDriverState **ptr = qdev_get_prop_ptr(dev, prop);
 
     if (*ptr) {
@@ -721,7 +726,7 @@ PropertyInfo qdev_prop_chr = {
     .size  = sizeof(CharDriverState*),
     .get   = get_chr,
     .set   = set_chr,
-    .free  = free_chr,
+    .release = release_chr,
 };
 
 /* --- netdev device --- */
diff --git a/hw/qdev.c b/hw/qdev.c
index 0205fe7..487ca5d 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -595,7 +595,7 @@ void qdev_property_add_static(DeviceState *dev, Property *prop,
 
     object_property_add(OBJECT(dev), prop->name, prop->info->name,
                         prop->info->get, prop->info->set,
-                        NULL,
+                        prop->info->release,
                         prop, errp);
 }
 
@@ -626,7 +626,6 @@ static void device_finalize(Object *obj)
 {
     DeviceState *dev = DEVICE(obj);
     BusState *bus;
-    Property *prop;
     DeviceClass *dc = DEVICE_GET_CLASS(dev);
 
     if (dev->state == DEV_STATE_INITIALIZED) {
@@ -645,11 +644,6 @@ static void device_finalize(Object *obj)
         }
     }
     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);
-        }
-    }
 }
 
 void device_reset(DeviceState *dev)
diff --git a/hw/qdev.h b/hw/qdev.h
index c31dc4e..acccf26 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -145,9 +145,9 @@ struct PropertyInfo {
     int64_t max;
     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);
     ObjectPropertyAccessor *get;
     ObjectPropertyAccessor *set;
+    ObjectPropertyRelease *release;
 };
 
 typedef struct GlobalProperty {
commit 7b009e5d09ee7786a4fd848327b6a8d8d7c01f0d
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Feb 2 13:01:40 2012 +0100

    qdev: remove parse/print methods for pointer properties
    
    Pointer properties (except for PROP_PTR of course) should not need a
    legacy counterpart.  In the future, relative paths will ensure that
    QEMU will support the same syntax as now for drives etc..
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 9a67cc5..67995a3 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -579,9 +579,8 @@ PropertyInfo qdev_prop_string = {
 
 /* --- drive --- */
 
-static int parse_drive(DeviceState *dev, Property *prop, const char *str)
+static int parse_drive(DeviceState *dev, const char *str, void **ptr)
 {
-    BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop);
     BlockDriverState *bs;
 
     bs = bdrv_find(str);
@@ -603,35 +602,30 @@ static void free_drive(DeviceState *dev, Property *prop)
     }
 }
 
-static int print_drive(DeviceState *dev, Property *prop, char *dest, size_t len)
+static const char *print_drive(void *ptr)
 {
-    BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop);
-    return snprintf(dest, len, "%s",
-                    *ptr ? bdrv_get_device_name(*ptr) : "<null>");
+    return bdrv_get_device_name(ptr);
 }
 
-static void get_generic(Object *obj, Visitor *v, void *opaque,
-                       const char *name, Error **errp)
+static void get_pointer(Object *obj, Visitor *v, Property *prop,
+                        const char *(*print)(void *ptr),
+                        const char *name, Error **errp)
 {
     DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
     void **ptr = qdev_get_prop_ptr(dev, prop);
-    char buffer[1024];
-    char *p = buffer;
+    char *p;
 
-    buffer[0] = 0;
-    if (*ptr) {
-        prop->info->print(dev, prop, buffer, sizeof(buffer));
-    }
+    p = (char *) (*ptr ? print(*ptr) : "");
     visit_type_str(v, &p, name, errp);
 }
 
-static void set_generic(Object *obj, Visitor *v, void *opaque,
+static void set_pointer(Object *obj, Visitor *v, Property *prop,
+                        int (*parse)(DeviceState *dev, const char *str, void **ptr),
                         const char *name, Error **errp)
 {
     DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
     Error *local_err = NULL;
+    void **ptr = qdev_get_prop_ptr(dev, prop);
     char *str;
     int ret;
 
@@ -650,36 +644,45 @@ static void set_generic(Object *obj, Visitor *v, void *opaque,
         error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
         return;
     }
-    ret = prop->info->parse(dev, prop, str);
+    ret = parse(dev, str, ptr);
     error_set_from_qdev_prop_error(errp, ret, dev, prop, str);
     g_free(str);
 }
 
+static void get_drive(Object *obj, Visitor *v, void *opaque,
+                      const char *name, Error **errp)
+{
+    get_pointer(obj, v, opaque, print_drive, name, errp);
+}
+
+static void set_drive(Object *obj, Visitor *v, void *opaque,
+                      const char *name, Error **errp)
+{
+    set_pointer(obj, v, opaque, parse_drive, name, errp);
+}
+
 PropertyInfo qdev_prop_drive = {
     .name  = "drive",
     .type  = PROP_TYPE_DRIVE,
     .size  = sizeof(BlockDriverState *),
-    .parse = parse_drive,
-    .print = print_drive,
-    .get   = get_generic,
-    .set   = set_generic,
+    .get   = get_drive,
+    .set   = set_drive,
     .free  = free_drive,
 };
 
 /* --- character device --- */
 
-static int parse_chr(DeviceState *dev, Property *prop, const char *str)
+static int parse_chr(DeviceState *dev, const char *str, void **ptr)
 {
-    CharDriverState **ptr = qdev_get_prop_ptr(dev, prop);
-
-    *ptr = qemu_chr_find(str);
-    if (*ptr == NULL) {
+    CharDriverState *chr = qemu_chr_find(str);
+    if (chr == NULL) {
         return -ENOENT;
     }
-    if ((*ptr)->avail_connections < 1) {
+    if (chr->avail_connections < 1) {
         return -EEXIST;
     }
-    --(*ptr)->avail_connections;
+    *ptr = chr;
+    --chr->avail_connections;
     return 0;
 }
 
@@ -693,62 +696,75 @@ static void free_chr(DeviceState *dev, Property *prop)
 }
 
 
-static int print_chr(DeviceState *dev, Property *prop, char *dest, size_t len)
+static const char *print_chr(void *ptr)
 {
-    CharDriverState **ptr = qdev_get_prop_ptr(dev, prop);
+    CharDriverState *chr = ptr;
 
-    if (*ptr && (*ptr)->label) {
-        return snprintf(dest, len, "%s", (*ptr)->label);
-    } else {
-        return snprintf(dest, len, "<null>");
-    }
+    return chr->label ? chr->label : "";
+}
+
+static void get_chr(Object *obj, Visitor *v, void *opaque,
+                    const char *name, Error **errp)
+{
+    get_pointer(obj, v, opaque, print_chr, name, errp);
+}
+
+static void set_chr(Object *obj, Visitor *v, void *opaque,
+                    const char *name, Error **errp)
+{
+    set_pointer(obj, v, opaque, parse_chr, name, errp);
 }
 
 PropertyInfo qdev_prop_chr = {
     .name  = "chr",
     .type  = PROP_TYPE_CHR,
     .size  = sizeof(CharDriverState*),
-    .parse = parse_chr,
-    .print = print_chr,
-    .get   = get_generic,
-    .set   = set_generic,
+    .get   = get_chr,
+    .set   = set_chr,
     .free  = free_chr,
 };
 
 /* --- netdev device --- */
 
-static int parse_netdev(DeviceState *dev, Property *prop, const char *str)
+static int parse_netdev(DeviceState *dev, const char *str, void **ptr)
 {
-    VLANClientState **ptr = qdev_get_prop_ptr(dev, prop);
+    VLANClientState *netdev = qemu_find_netdev(str);
 
-    *ptr = qemu_find_netdev(str);
-    if (*ptr == NULL)
+    if (netdev == NULL) {
         return -ENOENT;
-    if ((*ptr)->peer) {
+    }
+    if (netdev->peer) {
         return -EEXIST;
     }
+    *ptr = netdev;
     return 0;
 }
 
-static int print_netdev(DeviceState *dev, Property *prop, char *dest, size_t len)
+static const char *print_netdev(void *ptr)
 {
-    VLANClientState **ptr = qdev_get_prop_ptr(dev, prop);
+    VLANClientState *netdev = ptr;
 
-    if (*ptr && (*ptr)->name) {
-        return snprintf(dest, len, "%s", (*ptr)->name);
-    } else {
-        return snprintf(dest, len, "<null>");
-    }
+    return netdev->name ? netdev->name : "";
+}
+
+static void get_netdev(Object *obj, Visitor *v, void *opaque,
+                       const char *name, Error **errp)
+{
+    get_pointer(obj, v, opaque, print_netdev, name, errp);
+}
+
+static void set_netdev(Object *obj, Visitor *v, void *opaque,
+                       const char *name, Error **errp)
+{
+    set_pointer(obj, v, opaque, parse_netdev, name, errp);
 }
 
 PropertyInfo qdev_prop_netdev = {
     .name  = "netdev",
     .type  = PROP_TYPE_NETDEV,
     .size  = sizeof(VLANClientState*),
-    .parse = parse_netdev,
-    .print = print_netdev,
-    .get   = get_generic,
-    .set   = set_generic,
+    .get   = get_netdev,
+    .set   = set_netdev,
 };
 
 /* --- vlan --- */
commit b403298adb54ca683b895ebddd412dcb092cb780
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Feb 2 17:12:19 2012 +0100

    qdev: make the non-legacy pci address property accept an integer
    
    PCI addresses are set with qdev_prop_uint32.  Thus we make the QOM
    property accept a device and function encoded in an 8-bit integer,
    instead of the magic dd.f hex string.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 42b9b24..9a67cc5 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -999,30 +999,20 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t
     }
 }
 
-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];
-    char *p = buffer;
-
-    buffer[0] = 0;
-    if (*ptr != -1) {
-        snprintf(buffer, sizeof(buffer), "%02x.%x", *ptr >> 3, *ptr & 7);
-    }
-    visit_type_str(v, &p, name, errp);
-}
-
 PropertyInfo qdev_prop_pci_devfn = {
-    .name  = "pci-devfn",
+    .name  = "int32",
+    .legacy_name  = "pci-devfn",
     .type  = PROP_TYPE_UINT32,
     .size  = sizeof(uint32_t),
     .parse = parse_pci_devfn,
     .print = print_pci_devfn,
-    .get   = get_pci_devfn,
-    .set   = set_generic,
+    .get   = get_int32,
+    .set   = set_int32,
+    /* FIXME: this should be -1...255, but the address is stored
+     * into an uint32_t rather than int32_t.
+     */
+    .min   = 0,
+    .max   = 0xFFFFFFFFULL,
 };
 
 /* --- public helpers --- */
commit e39e5d60c9a65f36946454ddf8c9be9c582ffef8
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Feb 2 17:08:47 2012 +0100

    qdev: remove parse/print methods for mac properties
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index dea287a..42b9b24 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -848,46 +848,69 @@ PropertyInfo qdev_prop_ptr = {
  *   01:02:03:04:05:06
  *   01-02-03-04-05-06
  */
-static int parse_mac(DeviceState *dev, Property *prop, const char *str)
+static void get_mac(Object *obj, Visitor *v, void *opaque,
+                    const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    MACAddr *mac = qdev_get_prop_ptr(dev, prop);
+    char buffer[2 * 6 + 5 + 1];
+    char *p = buffer;
+
+    snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x",
+             mac->a[0], mac->a[1], mac->a[2],
+             mac->a[3], mac->a[4], mac->a[5]);
+
+    visit_type_str(v, &p, name, errp);
+}
+
+static void set_mac(Object *obj, Visitor *v, void *opaque,
+                    const char *name, Error **errp)
 {
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
     MACAddr *mac = qdev_get_prop_ptr(dev, prop);
+    Error *local_err = NULL;
     int i, pos;
-    char *p;
+    char *str, *p;
+
+    if (dev->state != DEV_STATE_CREATED) {
+        error_set(errp, QERR_PERMISSION_DENIED);
+        return;
+    }
+
+    visit_type_str(v, &str, name, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
 
     for (i = 0, pos = 0; i < 6; i++, pos += 3) {
         if (!qemu_isxdigit(str[pos]))
-            return -EINVAL;
+            goto inval;
         if (!qemu_isxdigit(str[pos+1]))
-            return -EINVAL;
+            goto inval;
         if (i == 5) {
             if (str[pos+2] != '\0')
-                return -EINVAL;
+                goto inval;
         } else {
             if (str[pos+2] != ':' && str[pos+2] != '-')
-                return -EINVAL;
+                goto inval;
         }
         mac->a[i] = strtol(str+pos, &p, 16);
     }
-    return 0;
-}
-
-static int print_mac(DeviceState *dev, Property *prop, char *dest, size_t len)
-{
-    MACAddr *mac = qdev_get_prop_ptr(dev, prop);
+    return;
 
-    return snprintf(dest, len, "%02x:%02x:%02x:%02x:%02x:%02x",
-                    mac->a[0], mac->a[1], mac->a[2],
-                    mac->a[3], mac->a[4], mac->a[5]);
+inval:
+    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
 }
 
 PropertyInfo qdev_prop_macaddr = {
     .name  = "macaddr",
     .type  = PROP_TYPE_MACADDR,
     .size  = sizeof(MACAddr),
-    .parse = parse_mac,
-    .print = print_mac,
-    .get   = get_generic,
-    .set   = set_generic,
+    .get   = get_mac,
+    .set   = set_mac,
 };
 
 
commit 1ce05125571e9dbbd16e1de0f8924fe45bef2bf0
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Feb 2 22:09:44 2012 +0100

    qdev: remove print/parse methods from LostTickPolicy properties
    
    Also generalize the code so that we can have more enum properties
    in the future.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 1fc77b5..dea287a 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -893,50 +893,50 @@ PropertyInfo qdev_prop_macaddr = {
 
 /* --- 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 const char *lost_tick_policy_table[LOST_TICK_MAX+1] = {
+    [LOST_TICK_DISCARD] = "discard",
+    [LOST_TICK_DELAY] = "delay",
+    [LOST_TICK_MERGE] = "merge",
+    [LOST_TICK_SLEW] = "slew",
+    [LOST_TICK_MAX] = NULL,
 };
 
-static int parse_lost_tick_policy(DeviceState *dev, Property *prop,
-                                  const char *str)
+QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
+
+static void get_enum(Object *obj, Visitor *v, void *opaque,
+                     const char *name, Error **errp)
 {
-    LostTickPolicy *ptr = qdev_get_prop_ptr(dev, prop);
-    int i;
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    int *ptr = qdev_get_prop_ptr(dev, prop);
 
-    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;
+    visit_type_enum(v, ptr, prop->info->enum_table,
+                    prop->info->name, prop->name, errp);
 }
 
-static int print_lost_tick_policy(DeviceState *dev, Property *prop, char *dest,
-                                  size_t len)
+static void set_enum(Object *obj, Visitor *v, void *opaque,
+                     const char *name, Error **errp)
 {
-    LostTickPolicy *ptr = qdev_get_prop_ptr(dev, prop);
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    int *ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (dev->state != DEV_STATE_CREATED) {
+        error_set(errp, QERR_PERMISSION_DENIED);
+        return;
+    }
 
-    return snprintf(dest, len, "%s", lost_tick_policy_table[*ptr].name);
+    visit_type_enum(v, ptr, prop->info->enum_table,
+                    prop->info->name, prop->name, errp);
 }
 
 PropertyInfo qdev_prop_losttickpolicy = {
-    .name  = "lost_tick_policy",
+    .name  = "LostTickPolicy",
     .type  = PROP_TYPE_LOSTTICKPOLICY,
     .size  = sizeof(LostTickPolicy),
-    .parse = parse_lost_tick_policy,
-    .print = print_lost_tick_policy,
-    .get   = get_generic,
-    .set   = set_generic,
+    .enum_table  = lost_tick_policy_table,
+    .get   = get_enum,
+    .set   = set_enum,
 };
 
 /* --- pci address --- */
diff --git a/hw/qdev.h b/hw/qdev.h
index ab53273..c31dc4e 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -140,6 +140,7 @@ struct PropertyInfo {
     const char *legacy_name;
     size_t size;
     enum PropertyType type;
+    const char **enum_table;
     int64_t min;
     int64_t max;
     int (*parse)(DeviceState *dev, Property *prop, const char *str);
diff --git a/qemu-common.h b/qemu-common.h
index 8b69a9e..9b997f8 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -255,6 +255,7 @@ typedef enum LostTickPolicy {
     LOST_TICK_DELAY,
     LOST_TICK_MERGE,
     LOST_TICK_SLEW,
+    LOST_TICK_MAX
 } LostTickPolicy;
 
 void tcg_exec_init(unsigned long tb_size);
commit acbac4a1dc974a3915760b4551336544c4360241
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Feb 2 13:04:45 2012 +0100

    qdev: remove parse method for string properties
    
    We need the print method to put double quotes, but parsing is not special.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 5e19ec8..1fc77b5 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -510,16 +510,6 @@ PropertyInfo qdev_prop_hex64 = {
 
 /* --- string --- */
 
-static int parse_string(DeviceState *dev, Property *prop, const char *str)
-{
-    char **ptr = qdev_get_prop_ptr(dev, prop);
-
-    if (*ptr)
-        g_free(*ptr);
-    *ptr = g_strdup(str);
-    return 0;
-}
-
 static void free_string(DeviceState *dev, Property *prop)
 {
     g_free(*(char **)qdev_get_prop_ptr(dev, prop));
@@ -581,7 +571,6 @@ PropertyInfo qdev_prop_string = {
     .name  = "string",
     .type  = PROP_TYPE_STRING,
     .size  = sizeof(char*),
-    .parse = parse_string,
     .print = print_string,
     .free  = free_string,
     .get   = get_string,
commit 68ee356941801d0a17fdc43b11ac3e6b72fcd597
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Feb 2 10:17:19 2012 +0100

    qdev: allow reusing get/set for legacy property
    
    In some cases, a legacy property does need a special print method
    but not a special parse method.  In this case, we can reuse the get/set
    from the static (non-legacy) property.
    
    If neither parse nor print is needed, though, do not register the
    legacy property at all.  The previous patch ensures that the right
    fallback will be used.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/qdev.c b/hw/qdev.c
index acb7829..0205fe7 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -550,21 +550,24 @@ static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque,
  * Do not use this is new code!  Properties added through this interface will
  * be given names and types in the "legacy" namespace.
  *
- * Legacy properties are always processed as strings.  The format of the string
- * depends on the property type.
+ * Legacy properties are string versions of other OOM properties.  The format
+ * of the string depends on the property type.
  */
 void qdev_property_add_legacy(DeviceState *dev, Property *prop,
                               Error **errp)
 {
     gchar *name, *type;
 
+    if (!prop->info->print && !prop->info->parse) {
+        return;
+    }
     name = g_strdup_printf("legacy-%s", prop->name);
     type = g_strdup_printf("legacy<%s>",
                            prop->info->legacy_name ?: prop->info->name);
 
     object_property_add(OBJECT(dev), name, type,
-                        prop->info->print ? qdev_get_legacy_property : NULL,
-                        prop->info->parse ? qdev_set_legacy_property : NULL,
+                        prop->info->print ? qdev_get_legacy_property : prop->info->get,
+                        prop->info->parse ? qdev_set_legacy_property : prop->info->set,
                         NULL,
                         prop, errp);
 
commit d822979bdf80c3ea9752615af15f231b4c4ce547
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Feb 2 09:47:13 2012 +0100

    qdev: remove direct calls to print/parse
    
    There's no need to call into ->parse and ->print manually.  The
    QOM legacy properties do that for us.
    
    Furthermore, in some cases legacy and static properties have exactly
    the same behavior, and we could drop the legacy properties right away.
    Add an appropriate fallback to prepare for this.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index 135c2bf..49f13ca 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -485,22 +485,26 @@ 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);
+    for (; props->name; props++) {
+        Error *err = NULL;
+        char *value;
+        char *legacy_name = g_strdup_printf("legacy-%s", props->name);
+        if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
+            value = object_property_get_str(OBJECT(dev), legacy_name, &err);
+        } else {
+            value = object_property_get_str(OBJECT(dev), props->name, &err);
+        }
+        g_free(legacy_name);
+
+        if (err) {
+            error_free(err);
+            continue;
         }
-        props++;
+        qdev_printf("%s-prop: %s = %s\n", prefix, props->name,
+                    value && *value ? value : "<null>");
+        g_free(value);
     }
 }
 
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index c4583a1..5e19ec8 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -1073,24 +1073,18 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
 
 int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
 {
-    Property *prop;
-    int ret;
+    char *legacy_name;
+    Error *err = NULL;
 
-    prop = qdev_prop_find(dev, name);
-    /*
-     * TODO Properties without a parse method are just for dirty
-     * hacks.  qdev_prop_ptr is the only such PropertyInfo.  It's
-     * marked for removal.  The test !prop->info->parse should be
-     * removed along with it.
-     */
-    if (!prop || !prop->info->parse) {
-        qerror_report(QERR_PROPERTY_NOT_FOUND, object_get_typename(OBJECT(dev)), name);
-        return -1;
+    legacy_name = g_strdup_printf("legacy-%s", name);
+    if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
+        object_property_set_str(OBJECT(dev), value, legacy_name, &err);
+    } else {
+        object_property_set_str(OBJECT(dev), value, name, &err);
     }
-    ret = prop->info->parse(dev, prop, value);
-    if (ret < 0) {
-        Error *err;
-        error_set_from_qdev_prop_error(&err, ret, dev, prop, value);
+    g_free(legacy_name);
+
+    if (err) {
         qerror_report_err(err);
         error_free(err);
         return -1;
diff --git a/hw/qdev.c b/hw/qdev.c
index e3b53b7..acb7829 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -581,6 +581,15 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop,
 void qdev_property_add_static(DeviceState *dev, Property *prop,
                               Error **errp)
 {
+    /*
+     * TODO qdev_prop_ptr does not have getters or setters.  It must
+     * go now that it can be replaced with links.  The test should be
+     * removed along with it: all static properties are read/write.
+     */
+    if (!prop->info->get && !prop->info->set) {
+        return;
+    }
+
     object_property_add(OBJECT(dev), prop->name, prop->info->name,
                         prop->info->get, prop->info->set,
                         NULL,
commit 1d9c5a12cefcd914d99c32de9aac72966a4788ae
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Feb 2 10:51:57 2012 +0100

    qom: add property get/set wrappers for links
    
    These can set a link to any object, as long as it is included in
    the composition tree.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/include/qemu/object.h b/include/qemu/object.h
index 6c36345..7d50da9 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -646,6 +646,30 @@ char *object_property_get_str(Object *obj, const char *name,
                               struct Error **errp);
 
 /**
+ * object_property_set_link:
+ * @value: the value to be written to the property
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Writes an object's canonical path to a property.
+ */
+void object_property_set_link(Object *obj, Object *value,
+                              const char *name, struct Error **errp);
+
+/**
+ * object_property_get_link:
+ * @obj: the object
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Returns: the value of the property, resolved from a path to an Object,
+ * or NULL if an error occurs (including when the property value is not a
+ * string or not a valid object path).
+ */
+Object *object_property_get_link(Object *obj, const char *name,
+                                 struct Error **errp);
+
+/**
  * object_property_set_bool:
  * @value: the value to be written to the property
  * @name: the name of the property
diff --git a/qom/object.c b/qom/object.c
index 686cca0..5e5b261 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -696,6 +696,30 @@ char *object_property_get_str(Object *obj, const char *name,
     return retval;
 }
 
+void object_property_set_link(Object *obj, Object *value,
+                              const char *name, Error **errp)
+{
+    object_property_set_str(obj, object_get_canonical_path(value),
+                            name, errp);
+}
+
+Object *object_property_get_link(Object *obj, const char *name,
+                                 Error **errp)
+{
+    char *str = object_property_get_str(obj, name, errp);
+    Object *target = NULL;
+
+    if (str && *str) {
+        target = object_resolve_path(str, NULL);
+        if (!target) {
+            error_set(errp, QERR_DEVICE_NOT_FOUND, str);
+        }
+    }
+
+    g_free(str);
+    return target;
+}
+
 void object_property_set_bool(Object *obj, bool value,
                               const char *name, Error **errp)
 {
commit a1e7efdcef38f7cba4a46e836f433c73d45d926f
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Feb 3 15:59:53 2012 +0100

    qom: fix canonical paths vs. interfaces
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/qom/object.c b/qom/object.c
index 2bd15b8..686cca0 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -805,6 +805,12 @@ void object_property_add_child(Object *obj, const char *name,
 {
     gchar *type;
 
+    /* Registering an interface object in the composition tree will mightily
+     * confuse object_get_canonical_path (which, on the other hand, knows how
+     * to get the canonical path of an interface object).
+     */
+    assert(!object_is_type(obj, type_interface));
+
     type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
 
     object_property_add(obj, name, type, object_get_child_property,
@@ -898,6 +904,10 @@ gchar *object_get_canonical_path(Object *obj)
     Object *root = object_get_root();
     char *newpath = NULL, *path = NULL;
 
+    if (object_is_type(obj, type_interface)) {
+        obj = INTERFACE(obj)->obj;
+    }
+
     while (obj != root) {
         ObjectProperty *prop = NULL;
 
commit 11e35bfdc7f030f65844b34239bdde16e68b2468
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Feb 2 12:37:53 2012 +0100

    qom: use object_resolve_path_type for links
    
    This allows to restrict partial matches to objects of the expected
    type.  It will let people use bare names to reference drives
    even though their name might be the same as a device's (e.g.
    -drive id=hd0,if=none,... -device ...,drive=hd0,id=hd0).
    
    As a useful byproduct, this fixes a problem with links of interface
    type.  When a link property's type is an interface, the code expects
    the implementation object (not the parent object) to be stored in the
    variable.  The parent object does not contain the right vtable.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/qerror.c b/qerror.c
index 3d179c8..8e6efaf 100644
--- a/qerror.c
+++ b/qerror.c
@@ -48,6 +48,10 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "Could not add client",
     },
     {
+        .error_fmt = QERR_AMBIGUOUS_PATH,
+        .desc      = "Path '%(path)' does not uniquely identify a %(object)"
+    },
+    {
         .error_fmt = QERR_BAD_BUS_FOR_DEVICE,
         .desc      = "Device '%(device)' can't go on a %(bad_bus_type) bus",
     },
diff --git a/qerror.h b/qerror.h
index 8c36ddb..e8718bf 100644
--- a/qerror.h
+++ b/qerror.h
@@ -54,6 +54,9 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_ADD_CLIENT_FAILED \
     "{ 'class': 'AddClientFailed', 'data': {} }"
 
+#define QERR_AMBIGUOUS_PATH \
+    "{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }"
+
 #define QERR_BAD_BUS_FOR_DEVICE \
     "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
 
diff --git a/qom/object.c b/qom/object.c
index ea0efc6..2bd15b8 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -840,6 +840,7 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
     bool ambiguous = false;
     const char *type;
     char *path;
+    gchar *target_type;
 
     type = object_property_get_type(obj, name, NULL);
 
@@ -847,28 +848,30 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
 
     if (*child) {
         object_unref(*child);
+        *child = NULL;
     }
 
     if (strcmp(path, "") != 0) {
         Object *target;
 
-        target = object_resolve_path(path, &ambiguous);
-        if (target) {
-            /* Go from link<FOO> to FOO.  */
-            gchar *target_type = g_strndup(&type[5], strlen(type) - 6);
-            if (object_dynamic_cast(target, target_type)) {
-                object_ref(target);
-                *child = target;
-            } else {
-                error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
-            }
+        /* Go from link<FOO> to FOO.  */
+        target_type = g_strndup(&type[5], strlen(type) - 6);
+        target = object_resolve_path_type(path, target_type, &ambiguous);
 
-            g_free(target_type);
+        if (ambiguous) {
+            error_set(errp, QERR_AMBIGUOUS_PATH, path);
+        } else if (target) {
+            object_ref(target);
+            *child = target;
         } else {
-            error_set(errp, QERR_DEVICE_NOT_FOUND, path);
+            target = object_resolve_path(path, &ambiguous);
+            if (target || ambiguous) {
+                error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type);
+            } else {
+                error_set(errp, QERR_DEVICE_NOT_FOUND, path);
+            }
         }
-    } else {
-        *child = NULL;
+        g_free(target_type);
     }
 
     g_free(path);
commit 02fe2db6312ff894be9aa0b862b383cc9d94505a
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Feb 3 11:21:01 2012 +0100

    qom: add object_resolve_path_type
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/include/qemu/object.h b/include/qemu/object.h
index b27f80e..6c36345 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -749,14 +749,35 @@ gchar *object_get_canonical_path(Object *obj);
  * specifying objects 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.
+ * only one match is found.  If more than one match is found, a flag is
+ * returned to indicate that the match was ambiguous.
  *
  * Returns: The matched object or NULL on path lookup failure.
  */
 Object *object_resolve_path(const char *path, bool *ambiguous);
 
 /**
+ * object_resolve_path_type:
+ * @path: the path to resolve
+ * @typename: the type to look for.
+ * @ambiguous: returns true if the path resolution failed because of an
+ *   ambiguous match
+ *
+ * This is similar to object_resolve_path.  However, when looking for a
+ * partial path only matches that implement the given type are considered.
+ * This restricts the search and avoids spuriously flagging matches as
+ * ambiguous.
+ *
+ * For both partial and absolute paths, the return value goes through
+ * a dynamic cast to @typename.  This is important if either the link,
+ * or the typename itself are of interface types.
+ *
+ * Returns: The matched object or NULL on path lookup failure.
+ */
+Object *object_resolve_path_type(const char *path, const char *typename,
+                                 bool *ambiguous);
+
+/**
  * object_property_add_child:
  * @obj: the object to add a property to
  * @name: the name of the property
diff --git a/qom/object.c b/qom/object.c
index 7fd37cb..ea0efc6 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -930,17 +930,18 @@ gchar *object_get_canonical_path(Object *obj)
 
 static Object *object_resolve_abs_path(Object *parent,
                                           gchar **parts,
+                                          const char *typename,
                                           int index)
 {
     ObjectProperty *prop;
     Object *child;
 
     if (parts[index] == NULL) {
-        return parent;
+        return object_dynamic_cast(parent, typename);
     }
 
     if (strcmp(parts[index], "") == 0) {
-        return object_resolve_abs_path(parent, parts, index + 1);
+        return object_resolve_abs_path(parent, parts, typename, index + 1);
     }
 
     prop = object_property_find(parent, parts[index]);
@@ -962,17 +963,18 @@ static Object *object_resolve_abs_path(Object *parent,
         return NULL;
     }
 
-    return object_resolve_abs_path(child, parts, index + 1);
+    return object_resolve_abs_path(child, parts, typename, index + 1);
 }
 
 static Object *object_resolve_partial_path(Object *parent,
                                               gchar **parts,
+                                              const char *typename,
                                               bool *ambiguous)
 {
     Object *obj;
     ObjectProperty *prop;
 
-    obj = object_resolve_abs_path(parent, parts, 0);
+    obj = object_resolve_abs_path(parent, parts, typename, 0);
 
     QTAILQ_FOREACH(prop, &parent->properties, node) {
         Object *found;
@@ -981,7 +983,8 @@ static Object *object_resolve_partial_path(Object *parent,
             continue;
         }
 
-        found = object_resolve_partial_path(prop->opaque, parts, ambiguous);
+        found = object_resolve_partial_path(prop->opaque, parts,
+                                            typename, ambiguous);
         if (found) {
             if (obj) {
                 if (ambiguous) {
@@ -1000,7 +1003,8 @@ static Object *object_resolve_partial_path(Object *parent,
     return obj;
 }
 
-Object *object_resolve_path(const char *path, bool *ambiguous)
+Object *object_resolve_path_type(const char *path, const char *typename,
+                                 bool *ambiguous)
 {
     bool partial_path = true;
     Object *obj;
@@ -1020,9 +1024,10 @@ Object *object_resolve_path(const char *path, bool *ambiguous)
         if (ambiguous) {
             *ambiguous = false;
         }
-        obj = object_resolve_partial_path(object_get_root(), parts, ambiguous);
+        obj = object_resolve_partial_path(object_get_root(), parts,
+                                          typename, ambiguous);
     } else {
-        obj = object_resolve_abs_path(object_get_root(), parts, 1);
+        obj = object_resolve_abs_path(object_get_root(), parts, typename, 1);
     }
 
     g_strfreev(parts);
@@ -1030,6 +1035,11 @@ Object *object_resolve_path(const char *path, bool *ambiguous)
     return obj;
 }
 
+Object *object_resolve_path(const char *path, bool *ambiguous)
+{
+    return object_resolve_path_type(path, TYPE_OBJECT, ambiguous);
+}
+
 typedef struct StringProperty
 {
     char *(*get)(Object *, Error **);
commit 8f770d39056c797a0a3de7a9a1a00befddfb088a
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Feb 3 15:41:13 2012 +0100

    qom: fix off-by-one
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/qom/object.c b/qom/object.c
index 212629d..7fd37cb 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -854,11 +854,8 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
 
         target = object_resolve_path(path, &ambiguous);
         if (target) {
-            gchar *target_type;
-
-            target_type = g_strdup(&type[5]);
-            target_type[strlen(target_type) - 2] = 0;
-
+            /* Go from link<FOO> to FOO.  */
+            gchar *target_type = g_strndup(&type[5], strlen(type) - 6);
             if (object_dynamic_cast(target, target_type)) {
                 object_ref(target);
                 *child = target;
commit 7b7b7d18e40c158134b7588e629be7dd35b468fa
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Feb 1 17:16:22 2012 +0100

    qom: add property get/set wrappers for C types
    
    Add wrappers that let you get/set properties using normal C data types.
    
    Reviewed-by: Anthony Liguori <anthony at aliguori@us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/include/qemu/object.h b/include/qemu/object.h
index ad7d32d..b27f80e 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -622,6 +622,76 @@ void object_property_get(Object *obj, struct Visitor *v, const char *name,
                          struct Error **errp);
 
 /**
+ * object_property_set_str:
+ * @value: the value to be written to the property
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Writes a string value to a property.
+ */
+void object_property_set_str(Object *obj, const char *value,
+                             const char *name, struct Error **errp);
+
+/**
+ * object_property_get_str:
+ * @obj: the object
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Returns: the value of the property, converted to a C string, or NULL if
+ * an error occurs (including when the property value is not a string).
+ * The caller should free the string.
+ */
+char *object_property_get_str(Object *obj, const char *name,
+                              struct Error **errp);
+
+/**
+ * object_property_set_bool:
+ * @value: the value to be written to the property
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Writes a bool value to a property.
+ */
+void object_property_set_bool(Object *obj, bool value,
+                              const char *name, struct Error **errp);
+
+/**
+ * object_property_get_bool:
+ * @obj: the object
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Returns: the value of the property, converted to a boolean, or NULL if
+ * an error occurs (including when the property value is not a bool).
+ */
+bool object_property_get_bool(Object *obj, const char *name,
+                              struct Error **errp);
+
+/**
+ * object_property_set_int:
+ * @value: the value to be written to the property
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Writes an integer value to a property.
+ */
+void object_property_set_int(Object *obj, int64_t value,
+                             const char *name, struct Error **errp);
+
+/**
+ * object_property_get_int:
+ * @obj: the object
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Returns: the value of the property, converted to an integer, or NULL if
+ * an error occurs (including when the property value is not an integer).
+ */
+int64_t object_property_get_int(Object *obj, const char *name,
+                                struct Error **errp);
+
+/**
  * object_property_set:
  * @obj: the object
  * @v: the visitor that will be used to write the property value.  This should
diff --git a/qom/object.c b/qom/object.c
index 98b8ad5..212629d 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -14,6 +14,14 @@
 #include "qemu-common.h"
 #include "qapi/qapi-visit-core.h"
 
+/* TODO: replace QObject with a simpler visitor to avoid a dependency
+ * of the QOM core on QObject?  */
+#include "qemu/qom-qobject.h"
+#include "qobject.h"
+#include "qbool.h"
+#include "qint.h"
+#include "qstring.h"
+
 #define MAX_INTERFACES 32
 
 typedef struct InterfaceImpl InterfaceImpl;
@@ -657,6 +665,99 @@ void object_property_set(Object *obj, Visitor *v, const char *name,
     }
 }
 
+void object_property_set_str(Object *obj, const char *value,
+                             const char *name, Error **errp)
+{
+    QString *qstr = qstring_from_str(value);
+    object_property_set_qobject(obj, QOBJECT(qstr), name, errp);
+
+    QDECREF(qstr);
+}
+
+char *object_property_get_str(Object *obj, const char *name,
+                              Error **errp)
+{
+    QObject *ret = object_property_get_qobject(obj, name, errp);
+    QString *qstring;
+    char *retval;
+
+    if (!ret) {
+        return NULL;
+    }
+    qstring = qobject_to_qstring(ret);
+    if (!qstring) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string");
+        retval = NULL;
+    } else {
+        retval = g_strdup(qstring_get_str(qstring));
+    }
+
+    QDECREF(qstring);
+    return retval;
+}
+
+void object_property_set_bool(Object *obj, bool value,
+                              const char *name, Error **errp)
+{
+    QBool *qbool = qbool_from_int(value);
+    object_property_set_qobject(obj, QOBJECT(qbool), name, errp);
+
+    QDECREF(qbool);
+}
+
+bool object_property_get_bool(Object *obj, const char *name,
+                              Error **errp)
+{
+    QObject *ret = object_property_get_qobject(obj, name, errp);
+    QBool *qbool;
+    bool retval;
+
+    if (!ret) {
+        return false;
+    }
+    qbool = qobject_to_qbool(ret);
+    if (!qbool) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean");
+        retval = false;
+    } else {
+        retval = qbool_get_int(qbool);
+    }
+
+    QDECREF(qbool);
+    return retval;
+}
+
+void object_property_set_int(Object *obj, int64_t value,
+                             const char *name, Error **errp)
+{
+    QInt *qint = qint_from_int(value);
+    object_property_set_qobject(obj, QOBJECT(qint), name, errp);
+
+    QDECREF(qint);
+}
+
+int64_t object_property_get_int(Object *obj, const char *name,
+                                Error **errp)
+{
+    QObject *ret = object_property_get_qobject(obj, name, errp);
+    QInt *qint;
+    int64_t retval;
+
+    if (!ret) {
+        return -1;
+    }
+    qint = qobject_to_qint(ret);
+    if (!qint) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "int");
+        retval = -1;
+    } else {
+        retval = qint_get_int(qint);
+    }
+
+    QDECREF(qint);
+    return retval;
+}
+
 const char *object_property_get_type(Object *obj, const char *name, Error **errp)
 {
     ObjectProperty *prop = object_property_find(obj, name);
@@ -938,8 +1039,8 @@ typedef struct StringProperty
     void (*set)(Object *, const char *, Error **);
 } StringProperty;
 
-static void object_property_get_str(Object *obj, Visitor *v, void *opaque,
-                                    const char *name, Error **errp)
+static void property_get_str(Object *obj, Visitor *v, void *opaque,
+                             const char *name, Error **errp)
 {
     StringProperty *prop = opaque;
     char *value;
@@ -951,8 +1052,8 @@ static void object_property_get_str(Object *obj, Visitor *v, void *opaque,
     }
 }
 
-static void object_property_set_str(Object *obj, Visitor *v, void *opaque,
-                                  const char *name, Error **errp)
+static void property_set_str(Object *obj, Visitor *v, void *opaque,
+                             const char *name, Error **errp)
 {
     StringProperty *prop = opaque;
     char *value;
@@ -968,8 +1069,8 @@ static void object_property_set_str(Object *obj, Visitor *v, void *opaque,
     g_free(value);
 }
 
-static void object_property_release_str(Object *obj, const char *name,
-                                      void *opaque)
+static void property_release_str(Object *obj, const char *name,
+                                 void *opaque)
 {
     StringProperty *prop = opaque;
     g_free(prop);
@@ -986,8 +1087,8 @@ void object_property_add_str(Object *obj, const char *name,
     prop->set = set;
 
     object_property_add(obj, name, "string",
-                        get ? object_property_get_str : NULL,
-                        set ? object_property_set_str : NULL,
-                        object_property_release_str,
+                        get ? property_get_str : NULL,
+                        set ? property_set_str : NULL,
+                        property_release_str,
                         prop, errp);
 }
commit 9f5f135058e22a6f7b3d8ca02e388e502c0d161f
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Feb 1 16:58:47 2012 +0100

    qom: add QObject-based property get/set wrappers
    
    Move the creation of QmpInputVisitor and QmpOutputVisitor from qmp.c
    to qom/object.c, since it's the only practical way to access object
    properties.
    
    Keep this isolated such that it's easy to remove.  At some point, we need
    to remove all usage of QObject in the tree and replace it with GVariant.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/include/qemu/qom-qobject.h b/include/qemu/qom-qobject.h
new file mode 100644
index 0000000..f9dff12
--- /dev/null
+++ b/include/qemu/qom-qobject.h
@@ -0,0 +1,42 @@
+/*
+ * QEMU Object Model - QObject wrappers
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * Author: Paolo Bonzini <pbonzini at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_QOM_QOBJECT_H
+#define QEMU_QOM_QOBJECT_H
+
+#include "qemu/object.h"
+
+/*
+ * object_property_get_qobject:
+ * @obj: the object
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Returns: the value of the property, converted to QObject, or NULL if
+ * an error occurs.
+ */
+struct QObject *object_property_get_qobject(Object *obj, const char *name,
+                                            struct Error **errp);
+
+/**
+ * object_property_set_qobject:
+ * @obj: the object
+ * @ret: The value that will be written to the property.
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Writes a property to a object.
+ */
+void object_property_set_qobject(Object *obj, struct QObject *qobj,
+                                 const char *name, struct Error **errp);
+
+#endif
diff --git a/qmp.c b/qmp.c
index 45052cc..1f64844 100644
--- a/qmp.c
+++ b/qmp.c
@@ -21,9 +21,8 @@
 #include "kvm.h"
 #include "arch_init.h"
 #include "hw/qdev.h"
-#include "qapi/qmp-input-visitor.h"
-#include "qapi/qmp-output-visitor.h"
 #include "blockdev.h"
+#include "qemu/qom-qobject.h"
 
 NameInfo *qmp_query_name(Error **errp)
 {
@@ -198,7 +197,6 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret)
     const char *property = qdict_get_str(qdict, "property");
     QObject *value = qdict_get(qdict, "value");
     Error *local_err = NULL;
-    QmpInputVisitor *mi;
     Object *obj;
 
     obj = object_resolve_path(path, NULL);
@@ -207,10 +205,7 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret)
         goto out;
     }
 
-    mi = qmp_input_visitor_new(value);
-    object_property_set(obj, qmp_input_get_visitor(mi), property, &local_err);
-
-    qmp_input_visitor_cleanup(mi);
+    object_property_set_qobject(obj, value, property, &local_err);
 
 out:
     if (local_err) {
@@ -227,7 +222,6 @@ int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret)
     const char *path = qdict_get_str(qdict, "path");
     const char *property = qdict_get_str(qdict, "property");
     Error *local_err = NULL;
-    QmpOutputVisitor *mo;
     Object *obj;
 
     obj = object_resolve_path(path, NULL);
@@ -236,13 +230,7 @@ int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret)
         goto out;
     }
 
-    mo = qmp_output_visitor_new();
-    object_property_get(obj, qmp_output_get_visitor(mo), property, &local_err);
-    if (!local_err) {
-        *ret = qmp_output_get_qobject(mo);
-    }
-
-    qmp_output_visitor_cleanup(mo);
+    *ret = object_property_get_qobject(obj, property, &local_err);
 
 out:
     if (local_err) {
diff --git a/qom/Makefile b/qom/Makefile
index f33f0be..885a263 100644
--- a/qom/Makefile
+++ b/qom/Makefile
@@ -1 +1 @@
-qom-y = object.o container.o
+qom-y = object.o container.o qom-qobject.o
diff --git a/qom/qom-qobject.c b/qom/qom-qobject.c
new file mode 100644
index 0000000..0689914
--- /dev/null
+++ b/qom/qom-qobject.c
@@ -0,0 +1,44 @@
+/*
+ * QEMU Object Model - QObject wrappers
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * Author: Paolo Bonzini <pbonzini at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+#include "qemu/object.h"
+#include "qemu/qom-qobject.h"
+#include "qapi/qapi-visit-core.h"
+#include "qapi/qmp-input-visitor.h"
+#include "qapi/qmp-output-visitor.h"
+
+void object_property_set_qobject(Object *obj, QObject *value,
+                                 const char *name, Error **errp)
+{
+    QmpInputVisitor *mi;
+    mi = qmp_input_visitor_new(value);
+    object_property_set(obj, qmp_input_get_visitor(mi), name, errp);
+
+    qmp_input_visitor_cleanup(mi);
+}
+
+QObject *object_property_get_qobject(Object *obj, const char *name,
+                                     Error **errp)
+{
+    QObject *ret = NULL;
+    Error *local_err = NULL;
+    QmpOutputVisitor *mo;
+
+    mo = qmp_output_visitor_new();
+    object_property_get(obj, qmp_output_get_visitor(mo), name, &local_err);
+    if (!local_err) {
+        ret = qmp_output_get_qobject(mo);
+    }
+    error_propagate(errp, local_err);
+    qmp_output_visitor_cleanup(mo);
+    return ret;
+}
commit b46d9b1082054cba5af5ccab584f0e22a5264057
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Feb 2 15:14:32 2012 +0100

    qom: do not include qdev header file
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/qom/object.c b/qom/object.c
index ffd50a3..98b8ad5 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -13,8 +13,6 @@
 #include "qemu/object.h"
 #include "qemu-common.h"
 #include "qapi/qapi-visit-core.h"
-#include "hw/qdev.h"
-// FIXME remove above
 
 #define MAX_INTERFACES 32
 
commit 9970bd887d7b6ec17899fa337e58547430a99e7d
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Feb 3 11:51:39 2012 +0100

    qom: avoid useless conversions from string to type
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/qom/object.c b/qom/object.c
index 669acc5..ffd50a3 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -63,6 +63,8 @@ typedef struct Interface
 
 #define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
 
+static Type type_interface;
+
 static GHashTable *type_table_get(void)
 {
     static GHashTable *type_table;
@@ -384,25 +386,20 @@ static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
     return false;
 }
 
-static bool object_is_type(Object *obj, const char *typename)
+static bool object_is_type(Object *obj, TypeImpl *target_type)
 {
-    TypeImpl *target_type;
-
-    if (typename == TYPE_OBJECT) {
-        return true;
-    }
-    target_type = type_get_by_name(typename);
-    return type_is_ancestor(obj->class->type, target_type);
+    return !target_type || type_is_ancestor(obj->class->type, target_type);
 }
 
 Object *object_dynamic_cast(Object *obj, const char *typename)
 {
+    TypeImpl *target_type = type_get_by_name(typename);
     GSList *i;
 
     /* Check if typename is a direct ancestor.  Special-case TYPE_OBJECT,
      * we want to go back from interfaces to the parent.
     */
-    if (typename && object_is_type(obj, typename)) {
+    if (target_type && object_is_type(obj, target_type)) {
         return obj;
     }
 
@@ -410,21 +407,21 @@ Object *object_dynamic_cast(Object *obj, const char *typename)
      * ancestor of typename.  In principle we could do this test at the very
      * beginning of object_dynamic_cast, avoiding a second call to
      * object_is_type.  However, casting between interfaces is relatively
-     * rare, and object_is_type(obj, TYPE_INTERFACE) would fail almost always.
+     * rare, and object_is_type(obj, type_interface) would fail almost always.
      *
      * Perhaps we could add a magic value to the object header for increased
      * (run-time) type safety and to speed up tests like this one.  If we ever
      * do that we can revisit the order here.
      */
-    if (object_is_type(obj, TYPE_INTERFACE)) {
+    if (object_is_type(obj, type_interface)) {
         assert(!obj->interfaces);
         obj = INTERFACE(obj)->obj;
-        if (object_is_type(obj, typename)) {
+        if (object_is_type(obj, target_type)) {
             return obj;
         }
     }
 
-    if (typename == TYPE_OBJECT) {
+    if (!target_type) {
         return obj;
     }
 
@@ -432,7 +429,7 @@ Object *object_dynamic_cast(Object *obj, const char *typename)
     for (i = obj->interfaces; i; i = i->next) {
         Interface *iface = i->data;
 
-        if (object_is_type(OBJECT(iface), typename)) {
+        if (object_is_type(OBJECT(iface), target_type)) {
             return OBJECT(iface);
         }
     }
@@ -449,7 +446,7 @@ static void register_interface(void)
         .abstract = true,
     };
 
-    type_register_static(&interface_info);
+    type_interface = type_register_static(&interface_info);
 }
 
 device_init(register_interface);
commit acc4af3fec335bb0778456f72bfb2c3591c11da4
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Feb 3 11:57:23 2012 +0100

    qom: clean up/optimize object_dynamic_cast
    
    The interface loop can be performed only on the parent object.  It
    does not need to be done on each interface.  Similarly, we can
    simplify the code by switching early from the implementation
    object to the parent object.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/qom/object.c b/qom/object.c
index 4261944..669acc5 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -368,11 +368,9 @@ void object_delete(Object *obj)
     g_free(obj);
 }
 
-static bool object_is_type(Object *obj, const char *typename)
+static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
 {
-    TypeImpl *target_type = type_get_by_name(typename);
-    TypeImpl *type = obj->class->type;
-    GSList *i;
+    assert(target_type);
 
     /* Check if typename is a direct ancestor of type */
     while (type) {
@@ -383,24 +381,50 @@ static bool object_is_type(Object *obj, const char *typename)
         type = type_get_parent(type);
     }
 
-    /* Check if obj has an interface of typename */
-    for (i = obj->interfaces; i; i = i->next) {
-        Interface *iface = i->data;
+    return false;
+}
 
-        if (object_is_type(OBJECT(iface), typename)) {
-            return true;
-        }
-    }
+static bool object_is_type(Object *obj, const char *typename)
+{
+    TypeImpl *target_type;
 
-    return false;
+    if (typename == TYPE_OBJECT) {
+        return true;
+    }
+    target_type = type_get_by_name(typename);
+    return type_is_ancestor(obj->class->type, target_type);
 }
 
 Object *object_dynamic_cast(Object *obj, const char *typename)
 {
     GSList *i;
 
-    /* Check if typename is a direct ancestor */
-    if (object_is_type(obj, typename)) {
+    /* Check if typename is a direct ancestor.  Special-case TYPE_OBJECT,
+     * we want to go back from interfaces to the parent.
+    */
+    if (typename && object_is_type(obj, typename)) {
+        return obj;
+    }
+
+    /* Check if obj is an interface and its containing object is a direct
+     * ancestor of typename.  In principle we could do this test at the very
+     * beginning of object_dynamic_cast, avoiding a second call to
+     * object_is_type.  However, casting between interfaces is relatively
+     * rare, and object_is_type(obj, TYPE_INTERFACE) would fail almost always.
+     *
+     * Perhaps we could add a magic value to the object header for increased
+     * (run-time) type safety and to speed up tests like this one.  If we ever
+     * do that we can revisit the order here.
+     */
+    if (object_is_type(obj, TYPE_INTERFACE)) {
+        assert(!obj->interfaces);
+        obj = INTERFACE(obj)->obj;
+        if (object_is_type(obj, typename)) {
+            return obj;
+        }
+    }
+
+    if (typename == TYPE_OBJECT) {
         return obj;
     }
 
@@ -413,16 +437,6 @@ Object *object_dynamic_cast(Object *obj, const char *typename)
         }
     }
 
-    /* Check if obj is an interface and its containing object is a direct
-     * ancestor of typename */
-    if (object_is_type(obj, TYPE_INTERFACE)) {
-        Interface *iface = INTERFACE(obj);
-
-        if (object_is_type(iface->obj, typename)) {
-            return iface->obj;
-        }
-    }
-
     return NULL;
 }
 
commit 0815a859492e87e120efa7feaa836ecf6ecffaf7
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Feb 3 12:51:53 2012 +0100

    qom: more documentation on subclassing
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/include/qemu/object.h b/include/qemu/object.h
index ab1c48c..ad7d32d 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -55,6 +55,9 @@ typedef struct InterfaceInfo InterfaceInfo;
  *
  * #define TYPE_MY_DEVICE "my-device"
  *
+ * // No new virtual functions: we can reuse the typedef for the
+ * // superclass.
+ * typedef DeviceClass MyDeviceClass;
  * typedef struct MyDevice
  * {
  *     DeviceState parent;
@@ -88,8 +91,21 @@ typedef struct InterfaceInfo InterfaceInfo;
  *
  * Using object_new(), a new #Object derivative will be instantiated.  You can
  * cast an #Object to a subclass (or base-class) type using
- * object_dynamic_cast().  You typically want to define a macro wrapper around
- * object_dynamic_cast_assert() to make it easier to convert to a specific type.
+ * object_dynamic_cast().  You typically want to define macro wrappers around
+ * OBJECT_CHECK() and OBJECT_CLASS_CHECK() to make it easier to convert to a
+ * specific type:
+ *
+ * <example>
+ *   <title>Typecasting macros</title>
+ *   <programlisting>
+ *    #define MY_DEVICE_GET_CLASS(obj) \
+ *       OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE)
+ *    #define MY_DEVICE_CLASS(klass) \
+ *       OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE)
+ *    #define MY_DEVICE(obj) \
+ *       OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE)
+ *   </programlisting>
+ * </example>
  *
  * # Class Initialization #
  *
@@ -108,7 +124,61 @@ typedef struct InterfaceInfo InterfaceInfo;
  *
  * Once all of the parent classes have been initialized, #TypeInfo::class_init
  * is called to let the class being instantiated provide default initialize for
- * it's virtual functions.
+ * it's virtual functions.  Here is how the above example might be modified
+ * to introduce an overridden virtual function:
+ *
+ * <example>
+ *   <title>Overriding a virtual function</title>
+ *   <programlisting>
+ * #include "qdev.h"
+ *
+ * void my_device_class_init(ObjectClass *klass, void *class_data)
+ * {
+ *     DeviceClass *dc = DEVICE_CLASS(klass);
+ *     dc->reset = my_device_reset;
+ * }
+ *
+ * static TypeInfo my_device_info = {
+ *     .name = TYPE_MY_DEVICE,
+ *     .parent = TYPE_DEVICE,
+ *     .instance_size = sizeof(MyDevice),
+ *     .class_init = my_device_class_init,
+ * };
+ *   </programlisting>
+ * </example>
+ *
+ * Introducing new virtual functions requires a class to define its own
+ * struct and to add a .class_size member to the TypeInfo.  Each function
+ * will also have a wrapper to call it easily:
+ *
+ * <example>
+ *   <title>Defining an abstract class</title>
+ *   <programlisting>
+ * #include "qdev.h"
+ *
+ * typedef struct MyDeviceClass
+ * {
+ *     DeviceClass parent;
+ *
+ *     void (*frobnicate) (MyDevice *obj);
+ * } MyDeviceClass;
+ *
+ * static TypeInfo my_device_info = {
+ *     .name = TYPE_MY_DEVICE,
+ *     .parent = TYPE_DEVICE,
+ *     .instance_size = sizeof(MyDevice),
+ *     .abstract = true, // or set a default in my_device_class_init
+ *     .class_size = sizeof(MyDeviceClass),
+ * };
+ *
+ * void my_device_frobnicate(MyDevice *obj)
+ * {
+ *     MyDeviceClass *klass = MY_DEVICE_GET_CLASS(obj);
+ *
+ *     klass->frobnicate(obj);
+ * }
+ *   </programlisting>
+ * </example>
  *
  * # Interfaces #
  *
commit 1ed5b918ceda9a92dd00a2d432aa431bea2da66a
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Feb 3 11:48:11 2012 +0100

    qom: clean up cast macros
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>

diff --git a/include/qemu/object.h b/include/qemu/object.h
index 9d0251d..ab1c48c 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -259,6 +259,16 @@ struct TypeInfo
     ((Object *)(obj))
 
 /**
+ * OBJECT_CLASS:
+ * @class: A derivative of #ObjectClas.
+ *
+ * Converts a class to an #ObjectClass.  Since all objects are #Objects,
+ * this function will always succeed.
+ */
+#define OBJECT_CLASS(class) \
+    ((ObjectClass *)(class))
+
+/**
  * OBJECT_CHECK:
  * @type: The C type to use for the return value.
  * @obj: A derivative of @type to cast.
@@ -272,7 +282,7 @@ struct TypeInfo
  * generated.
  */
 #define OBJECT_CHECK(type, obj, name) \
-    ((type *)object_dynamic_cast_assert((Object *)(obj), (name)))
+    ((type *)object_dynamic_cast_assert(OBJECT(obj), (name)))
 
 /**
  * OBJECT_CLASS_CHECK:
@@ -280,11 +290,12 @@ struct TypeInfo
  * @obj: A derivative of @type to cast.
  * @name: the QOM typename of @class.
  *
- * A type safe version of @object_check_class.  This macro is typically wrapped
- * by each type to perform type safe casts of a class to a specific class type.
+ * A type safe version of @object_class_dynamic_cast_assert.  This macro is
+ * typically wrapped by each type to perform type safe casts of a class to a
+ * specific class type.
  */
 #define OBJECT_CLASS_CHECK(class, obj, name) \
-    ((class *)object_class_dynamic_cast_assert((ObjectClass *)(obj), (name)))
+    ((class *)object_class_dynamic_cast_assert(OBJECT_CLASS(obj), (name)))
 
 /**
  * OBJECT_GET_CLASS:
@@ -299,9 +310,6 @@ struct TypeInfo
 #define OBJECT_GET_CLASS(class, obj, name) \
     OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
 
-#define OBJECT_CLASS(class) \
-    ((ObjectClass *)(class))
-
 /**
  * InterfaceClass:
  * @parent_class: the base class
commit e87f7fc67948da80a0452c4fd523ec45f0d03f26
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Feb 6 11:07:18 2012 -0600

    s390x: fix qom-ification fall-out
    
    Tested-by: Andreas Faerber <afaerber at suse.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index b66ef68..49140f8 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -429,6 +429,7 @@ static TypeInfo virtio_s390_device_info = {
     .parent = TYPE_DEVICE,
     .instance_size = sizeof(VirtIOS390Device),
     .class_init = virtio_s390_device_class_init,
+    .class_size = sizeof(VirtIOS390DeviceClass),
     .abstract = true,
 };
 
diff --git a/vl.c b/vl.c
index 2d464cf..63dd725 100644
--- a/vl.c
+++ b/vl.c
@@ -1947,7 +1947,11 @@ static int virtcon_parse(const char *devname)
     }
 
     bus_opts = qemu_opts_create(device, NULL, 0);
-    qemu_opt_set(bus_opts, "driver", "virtio-serial");
+    if (arch_type == QEMU_ARCH_S390X) {
+        qemu_opt_set(bus_opts, "driver", "virtio-serial-s390");
+    } else {
+        qemu_opt_set(bus_opts, "driver", "virtio-serial-pci");
+    } 
 
     dev_opts = qemu_opts_create(device, NULL, 0);
     qemu_opt_set(dev_opts, "driver", "virtconsole");
commit 4cafe606040bfb7526a954e131daa61afc5d747a
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Fri Feb 3 22:06:47 2012 +0100

    KVM: Fix breakages of QOM conversion
    
    KVM APIC and PIC require instance sizes.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c
index 89e33b0..dfc2ab3 100644
--- a/hw/kvm/apic.c
+++ b/hw/kvm/apic.c
@@ -135,6 +135,7 @@ static void kvm_apic_class_init(ObjectClass *klass, void *data)
 static TypeInfo kvm_apic_info = {
     .name = "kvm-apic",
     .parent = TYPE_APIC_COMMON,
+    .instance_size = sizeof(APICCommonState),
     .class_init = kvm_apic_class_init,
 };
 
diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c
index 297d64e..14bd427 100644
--- a/hw/kvm/i8259.c
+++ b/hw/kvm/i8259.c
@@ -126,6 +126,7 @@ static void kvm_i8259_class_init(ObjectClass *klass, void *data)
 static TypeInfo kvm_i8259_info = {
     .name  = "kvm-i8259",
     .parent = TYPE_PIC_COMMON,
+    .instance_size = sizeof(PICCommonState),
     .class_init = kvm_i8259_class_init,
 };
 
commit 3bc36349722a6f0d96ec9d8dc870aa82ae6de4cd
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Feb 3 17:39:57 2012 -0600

    usb-redir: convert to QOM
    
    This was missed due to the fact that it's in the top level and it uses
    'struct DeviceInfo' instead of 'DeviceInfo' for some strange reason.
    
    Tested-by: Benoît Canet <benoit.canet at gmail.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/usb-redir.c b/usb-redir.c
index 8f4a29a..303292a 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -1315,9 +1315,16 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id,
     }
 }
 
+static Property usbredir_properties[] = {
+    DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
+    DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
 static void usbredir_class_initfn(ObjectClass *klass, void *data)
 {
     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
 
     uc->init           = usbredir_initfn;
     uc->product_desc   = "USB Redirection Device";
@@ -1327,21 +1334,18 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data)
     uc->handle_reset   = usbredir_handle_reset;
     uc->handle_data    = usbredir_handle_data;
     uc->handle_control = usbredir_handle_control;
+    dc->props          = usbredir_properties;
 }
 
-static struct DeviceInfo usbredir_dev_info = {
-    .name      = "usb-redir",
-    .size      = sizeof(USBRedirDevice),
-    .class_init= usbredir_class_initfn,
-    .props     = (Property[]) {
-        DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
-        DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static TypeInfo usbredir_dev_info = {
+    .name          = "usb-redir",
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(USBRedirDevice),
+    .class_init    = usbredir_class_initfn,
 };
 
 static void usbredir_register_devices(void)
 {
-    usb_qdev_register(&usbredir_dev_info, NULL, NULL);
+    type_register_static(&usbredir_dev_info);
 }
 device_init(usbredir_register_devices);
commit 53a19a30527863f0257436de28d2b01ae043aaf0
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Feb 4 17:29:00 2012 +0000

    Fix previous commit
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/usb-bsd.c b/usb-bsd.c
index 43fd1a1..fc722b3 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -414,7 +414,7 @@ static TypeInfo usb_host_dev_info = {
     .name          = "usb-host",
     .parent        = TYPE_USB_DEVICE,
     .instance_size = sizeof(USBHostDevice),
-    .class_init    = usb_host_initfn,
+    .class_init    = usb_host_class_initfn,
 };
 
 static void usb_host_register_devices(void)
commit d217d208b5b518251196fbadd7f2fb1ed246cb13
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Feb 3 17:41:59 2012 -0600

    usb-bsd: convert to QOM
    
    Simple enough.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/usb-bsd.c b/usb-bsd.c
index 2c6afc8..43fd1a1 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -410,15 +410,16 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data)
     uc->handle_destroy = usb_host_handle_destroy;
 }
 
-static struct DeviceInfo usb_host_dev_info = {
-    .name      = "usb-host",
-    .size      = sizeof(USBHostDevice),
-    .class_init= usb_host_initfn,
+static TypeInfo usb_host_dev_info = {
+    .name          = "usb-host",
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(USBHostDevice),
+    .class_init    = usb_host_initfn,
 };
 
 static void usb_host_register_devices(void)
 {
-    usb_qdev_register(&usb_host_dev_info, NULL, NULL);
+    type_register_static(&usb_host_dev_info);
 }
 device_init(usb_host_register_devices)
 
commit 47c012e21cb368d9bf6be80cce8322c1e4481aa6
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Jan 29 17:29:12 2012 +0000

    vga: improve documentation
    
    Add links to chipset docs and FreeVGA site.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/vga.c b/hw/vga.c
index 758bd92..d87c4f9 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -37,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,
commit 5e55efc9e751e8044f5b870e069e4ed8165a2a84
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Jan 29 17:02:07 2012 +0000

    vga: use constants from vga.h
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/vga.c b/hw/vga.c
index cf9b39f..758bd92 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"
@@ -160,9 +161,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 +225,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 +261,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 +332,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 +350,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 +447,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 +478,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 +513,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 +687,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 +774,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 +797,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 +834,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,11 +857,11 @@ 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);
@@ -856,11 +869,11 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
             s->plane_updated |= mask; /* only used to detect font change */
             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
@@ -871,40 +884,41 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
         }
     } 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 +945,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] =
@@ -1045,10 +1059,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 +1119,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 +1232,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 +1291,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 +1339,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 +1351,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 +1397,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 +1565,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 +1623,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 +1642,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 +1690,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 +1698,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 +1743,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,13 +1756,13 @@ 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;
@@ -1769,7 +1792,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++;
@@ -1841,7 +1864,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;
@@ -1959,7 +1982,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;
@@ -1976,20 +1999,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;
         }
 
@@ -2018,11 +2043,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),
@@ -2030,8 +2056,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_int.h b/hw/vga_int.h
index f755582..7685b2b 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
 
diff --git a/hw/vga_template.h b/hw/vga_template.h
index 7150573..f6f6a01 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];
commit 0dad6c35fc58df753e84f09983ea98a1598e9d4a
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Jan 29 15:29:02 2012 +0000

    vga.h: remove unused stuff and reformat
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/vga.h b/hw/vga.h
index faf9c66..d917046 100644
--- a/hw/vga.h
+++ b/hw/vga.h
@@ -17,34 +17,6 @@
 #ifndef __linux_video_vga_h__
 #define __linux_video_vga_h__
 
-#include <linux/types.h>
-#include <asm/io.h>
-#ifndef CONFIG_AMIGA
-#include <asm/vga.h>
-#else
-/*
- * FIXME
- * Ugh, we don't have PCI space, so map readb() and friends to use Zorro space
- * for MMIO accesses. This should make cirrusfb work again on Amiga
- */
-#undef inb_p
-#undef inw_p
-#undef outb_p
-#undef outw
-#undef readb
-#undef writeb
-#undef writew
-#define inb_p(port)	0
-#define inw_p(port)	0
-#define outb_p(port, val)	do { } while (0)
-#define outw(port, val)		do { } while (0)
-#define readb		z_readb
-#define writeb		z_writeb
-#define writew		z_writew
-#endif
-#include <asm/byteorder.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                    */
@@ -57,425 +29,131 @@
 /* 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 */
+#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 */
+#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 */
+#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 */
+#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
+#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
+#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_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
+#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
+#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 */
+#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
+#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
-
-/* macro for composing an 8-bit VGA register index and value
- * into a single 16-bit quantity */
-#define VGA_OUT16VAL(v, r)       (((v) << 8) | (r))
-
-/* decide whether we should enable the faster 16-bit VGA register writes */
-#ifdef __LITTLE_ENDIAN
-#define VGA_OUTW_WRITE
-#endif
-
-/* VGA State Save and Restore */
-#define VGA_SAVE_FONT0 1  /* save/restore plane 2 fonts	  */
-#define VGA_SAVE_FONT1 2  /* save/restore plane 3 fonts   */
-#define VGA_SAVE_TEXT  4  /* save/restore plane 0/1 fonts */
-#define VGA_SAVE_FONTS 7  /* save/restore all fonts	  */
-#define VGA_SAVE_MODE  8  /* save/restore video mode 	  */
-#define VGA_SAVE_CMAP  16 /* save/restore color map/DAC   */
-
-struct vgastate {
-	void __iomem *vgabase;	/* mmio base, if supported 		   */
-	unsigned long membase;	/* VGA window base, 0 for default - 0xA000 */
-	__u32 memsize;		/* VGA window size, 0 for default 64K	   */
-	__u32 flags;		/* what state[s] to save (see VGA_SAVE_*)  */
-	__u32 depth;		/* current fb depth, not important	   */
-	__u32 num_attr;		/* number of att registers, 0 for default  */
-	__u32 num_crtc;		/* number of crt registers, 0 for default  */
-	__u32 num_gfx;		/* number of gfx registers, 0 for default  */
-	__u32 num_seq;		/* number of seq registers, 0 for default  */
-	void *vidstate;
-};
-
-extern int save_vga(struct vgastate *state);
-extern int restore_vga(struct vgastate *state);
-
-/*
- * generic VGA port read/write
- */
-
-static inline unsigned char vga_io_r (unsigned short port)
-{
-	return inb_p(port);
-}
-
-static inline void vga_io_w (unsigned short port, unsigned char val)
-{
-	outb_p(val, port);
-}
-
-static inline void vga_io_w_fast (unsigned short port, unsigned char reg,
-				  unsigned char val)
-{
-	outw(VGA_OUT16VAL (val, reg), port);
-}
-
-static inline unsigned char vga_mm_r (void __iomem *regbase, unsigned short port)
-{
-	return readb (regbase + port);
-}
-
-static inline void vga_mm_w (void __iomem *regbase, unsigned short port, unsigned char val)
-{
-	writeb (val, regbase + port);
-}
-
-static inline void vga_mm_w_fast (void __iomem *regbase, unsigned short port,
-				  unsigned char reg, unsigned char val)
-{
-	writew (VGA_OUT16VAL (val, reg), regbase + port);
-}
-
-static inline unsigned char vga_r (void __iomem *regbase, unsigned short port)
-{
-	if (regbase)
-		return vga_mm_r (regbase, port);
-	else
-		return vga_io_r (port);
-}
-
-static inline void vga_w (void __iomem *regbase, unsigned short port, unsigned char val)
-{
-	if (regbase)
-		vga_mm_w (regbase, port, val);
-	else
-		vga_io_w (port, val);
-}
-
-
-static inline void vga_w_fast (void __iomem *regbase, unsigned short port,
-			       unsigned char reg, unsigned char val)
-{
-	if (regbase)
-		vga_mm_w_fast (regbase, port, reg, val);
-	else
-		vga_io_w_fast (port, reg, val);
-}
-
-
-/*
- * VGA CRTC register read/write
- */
-
-static inline unsigned char vga_rcrt (void __iomem *regbase, unsigned char reg)
-{
-        vga_w (regbase, VGA_CRT_IC, reg);
-        return vga_r (regbase, VGA_CRT_DC);
-}
-
-static inline void vga_wcrt (void __iomem *regbase, unsigned char reg, unsigned char val)
-{
-#ifdef VGA_OUTW_WRITE
-	vga_w_fast (regbase, VGA_CRT_IC, reg, val);
-#else
-        vga_w (regbase, VGA_CRT_IC, reg);
-        vga_w (regbase, VGA_CRT_DC, val);
-#endif /* VGA_OUTW_WRITE */
-}
-
-static inline unsigned char vga_io_rcrt (unsigned char reg)
-{
-        vga_io_w (VGA_CRT_IC, reg);
-        return vga_io_r (VGA_CRT_DC);
-}
-
-static inline void vga_io_wcrt (unsigned char reg, unsigned char val)
-{
-#ifdef VGA_OUTW_WRITE
-	vga_io_w_fast (VGA_CRT_IC, reg, val);
-#else
-        vga_io_w (VGA_CRT_IC, reg);
-        vga_io_w (VGA_CRT_DC, val);
-#endif /* VGA_OUTW_WRITE */
-}
-
-static inline unsigned char vga_mm_rcrt (void __iomem *regbase, unsigned char reg)
-{
-        vga_mm_w (regbase, VGA_CRT_IC, reg);
-        return vga_mm_r (regbase, VGA_CRT_DC);
-}
-
-static inline void vga_mm_wcrt (void __iomem *regbase, unsigned char reg, unsigned char val)
-{
-#ifdef VGA_OUTW_WRITE
-	vga_mm_w_fast (regbase, VGA_CRT_IC, reg, val);
-#else
-        vga_mm_w (regbase, VGA_CRT_IC, reg);
-        vga_mm_w (regbase, VGA_CRT_DC, val);
-#endif /* VGA_OUTW_WRITE */
-}
-
-
-/*
- * VGA sequencer register read/write
- */
-
-static inline unsigned char vga_rseq (void __iomem *regbase, unsigned char reg)
-{
-        vga_w (regbase, VGA_SEQ_I, reg);
-        return vga_r (regbase, VGA_SEQ_D);
-}
-
-static inline void vga_wseq (void __iomem *regbase, unsigned char reg, unsigned char val)
-{
-#ifdef VGA_OUTW_WRITE
-	vga_w_fast (regbase, VGA_SEQ_I, reg, val);
-#else
-        vga_w (regbase, VGA_SEQ_I, reg);
-        vga_w (regbase, VGA_SEQ_D, val);
-#endif /* VGA_OUTW_WRITE */
-}
-
-static inline unsigned char vga_io_rseq (unsigned char reg)
-{
-        vga_io_w (VGA_SEQ_I, reg);
-        return vga_io_r (VGA_SEQ_D);
-}
-
-static inline void vga_io_wseq (unsigned char reg, unsigned char val)
-{
-#ifdef VGA_OUTW_WRITE
-	vga_io_w_fast (VGA_SEQ_I, reg, val);
-#else
-        vga_io_w (VGA_SEQ_I, reg);
-        vga_io_w (VGA_SEQ_D, val);
-#endif /* VGA_OUTW_WRITE */
-}
-
-static inline unsigned char vga_mm_rseq (void __iomem *regbase, unsigned char reg)
-{
-        vga_mm_w (regbase, VGA_SEQ_I, reg);
-        return vga_mm_r (regbase, VGA_SEQ_D);
-}
-
-static inline void vga_mm_wseq (void __iomem *regbase, unsigned char reg, unsigned char val)
-{
-#ifdef VGA_OUTW_WRITE
-	vga_mm_w_fast (regbase, VGA_SEQ_I, reg, val);
-#else
-        vga_mm_w (regbase, VGA_SEQ_I, reg);
-        vga_mm_w (regbase, VGA_SEQ_D, val);
-#endif /* VGA_OUTW_WRITE */
-}
-
-/*
- * VGA graphics controller register read/write
- */
-
-static inline unsigned char vga_rgfx (void __iomem *regbase, unsigned char reg)
-{
-        vga_w (regbase, VGA_GFX_I, reg);
-        return vga_r (regbase, VGA_GFX_D);
-}
-
-static inline void vga_wgfx (void __iomem *regbase, unsigned char reg, unsigned char val)
-{
-#ifdef VGA_OUTW_WRITE
-	vga_w_fast (regbase, VGA_GFX_I, reg, val);
-#else
-        vga_w (regbase, VGA_GFX_I, reg);
-        vga_w (regbase, VGA_GFX_D, val);
-#endif /* VGA_OUTW_WRITE */
-}
-
-static inline unsigned char vga_io_rgfx (unsigned char reg)
-{
-        vga_io_w (VGA_GFX_I, reg);
-        return vga_io_r (VGA_GFX_D);
-}
-
-static inline void vga_io_wgfx (unsigned char reg, unsigned char val)
-{
-#ifdef VGA_OUTW_WRITE
-	vga_io_w_fast (VGA_GFX_I, reg, val);
-#else
-        vga_io_w (VGA_GFX_I, reg);
-        vga_io_w (VGA_GFX_D, val);
-#endif /* VGA_OUTW_WRITE */
-}
-
-static inline unsigned char vga_mm_rgfx (void __iomem *regbase, unsigned char reg)
-{
-        vga_mm_w (regbase, VGA_GFX_I, reg);
-        return vga_mm_r (regbase, VGA_GFX_D);
-}
-
-static inline void vga_mm_wgfx (void __iomem *regbase, unsigned char reg, unsigned char val)
-{
-#ifdef VGA_OUTW_WRITE
-	vga_mm_w_fast (regbase, VGA_GFX_I, reg, val);
-#else
-        vga_mm_w (regbase, VGA_GFX_I, reg);
-        vga_mm_w (regbase, VGA_GFX_D, val);
-#endif /* VGA_OUTW_WRITE */
-}
-
-
-/*
- * VGA attribute controller register read/write
- */
-
-static inline unsigned char vga_rattr (void __iomem *regbase, unsigned char reg)
-{
-        vga_w (regbase, VGA_ATT_IW, reg);
-        return vga_r (regbase, VGA_ATT_R);
-}
-
-static inline void vga_wattr (void __iomem *regbase, unsigned char reg, unsigned char val)
-{
-        vga_w (regbase, VGA_ATT_IW, reg);
-        vga_w (regbase, VGA_ATT_W, val);
-}
-
-static inline unsigned char vga_io_rattr (unsigned char reg)
-{
-        vga_io_w (VGA_ATT_IW, reg);
-        return vga_io_r (VGA_ATT_R);
-}
-
-static inline void vga_io_wattr (unsigned char reg, unsigned char val)
-{
-        vga_io_w (VGA_ATT_IW, reg);
-        vga_io_w (VGA_ATT_W, val);
-}
-
-static inline unsigned char vga_mm_rattr (void __iomem *regbase, unsigned char reg)
-{
-        vga_mm_w (regbase, VGA_ATT_IW, reg);
-        return vga_mm_r (regbase, VGA_ATT_R);
-}
-
-static inline void vga_mm_wattr (void __iomem *regbase, unsigned char reg, unsigned char val)
-{
-        vga_mm_w (regbase, VGA_ATT_IW, reg);
-        vga_mm_w (regbase, VGA_ATT_W, val);
-}
+#define VGA_GR06_GRAPHICS_MODE  0x01
 
 #endif /* __linux_video_vga_h__ */
commit b134886a9eb422c1b687293953e400162599cd8a
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Jan 29 15:23:50 2012 +0000

    Add vga.h unmodified from Linux
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/vga.h b/hw/vga.h
new file mode 100644
index 0000000..faf9c66
--- /dev/null
+++ b/hw/vga.h
@@ -0,0 +1,481 @@
+/*
+ * linux/include/video/vga.h -- standard VGA chipset interaction
+ *
+ * Copyright 1999 Jeff Garzik <jgarzik at 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__
+
+#include <linux/types.h>
+#include <asm/io.h>
+#ifndef CONFIG_AMIGA
+#include <asm/vga.h>
+#else
+/*
+ * FIXME
+ * Ugh, we don't have PCI space, so map readb() and friends to use Zorro space
+ * for MMIO accesses. This should make cirrusfb work again on Amiga
+ */
+#undef inb_p
+#undef inw_p
+#undef outb_p
+#undef outw
+#undef readb
+#undef writeb
+#undef writew
+#define inb_p(port)	0
+#define inw_p(port)	0
+#define outb_p(port, val)	do { } while (0)
+#define outw(port, val)		do { } while (0)
+#define readb		z_readb
+#define writeb		z_writeb
+#define writew		z_writew
+#endif
+#include <asm/byteorder.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
+
+/* macro for composing an 8-bit VGA register index and value
+ * into a single 16-bit quantity */
+#define VGA_OUT16VAL(v, r)       (((v) << 8) | (r))
+
+/* decide whether we should enable the faster 16-bit VGA register writes */
+#ifdef __LITTLE_ENDIAN
+#define VGA_OUTW_WRITE
+#endif
+
+/* VGA State Save and Restore */
+#define VGA_SAVE_FONT0 1  /* save/restore plane 2 fonts	  */
+#define VGA_SAVE_FONT1 2  /* save/restore plane 3 fonts   */
+#define VGA_SAVE_TEXT  4  /* save/restore plane 0/1 fonts */
+#define VGA_SAVE_FONTS 7  /* save/restore all fonts	  */
+#define VGA_SAVE_MODE  8  /* save/restore video mode 	  */
+#define VGA_SAVE_CMAP  16 /* save/restore color map/DAC   */
+
+struct vgastate {
+	void __iomem *vgabase;	/* mmio base, if supported 		   */
+	unsigned long membase;	/* VGA window base, 0 for default - 0xA000 */
+	__u32 memsize;		/* VGA window size, 0 for default 64K	   */
+	__u32 flags;		/* what state[s] to save (see VGA_SAVE_*)  */
+	__u32 depth;		/* current fb depth, not important	   */
+	__u32 num_attr;		/* number of att registers, 0 for default  */
+	__u32 num_crtc;		/* number of crt registers, 0 for default  */
+	__u32 num_gfx;		/* number of gfx registers, 0 for default  */
+	__u32 num_seq;		/* number of seq registers, 0 for default  */
+	void *vidstate;
+};
+
+extern int save_vga(struct vgastate *state);
+extern int restore_vga(struct vgastate *state);
+
+/*
+ * generic VGA port read/write
+ */
+
+static inline unsigned char vga_io_r (unsigned short port)
+{
+	return inb_p(port);
+}
+
+static inline void vga_io_w (unsigned short port, unsigned char val)
+{
+	outb_p(val, port);
+}
+
+static inline void vga_io_w_fast (unsigned short port, unsigned char reg,
+				  unsigned char val)
+{
+	outw(VGA_OUT16VAL (val, reg), port);
+}
+
+static inline unsigned char vga_mm_r (void __iomem *regbase, unsigned short port)
+{
+	return readb (regbase + port);
+}
+
+static inline void vga_mm_w (void __iomem *regbase, unsigned short port, unsigned char val)
+{
+	writeb (val, regbase + port);
+}
+
+static inline void vga_mm_w_fast (void __iomem *regbase, unsigned short port,
+				  unsigned char reg, unsigned char val)
+{
+	writew (VGA_OUT16VAL (val, reg), regbase + port);
+}
+
+static inline unsigned char vga_r (void __iomem *regbase, unsigned short port)
+{
+	if (regbase)
+		return vga_mm_r (regbase, port);
+	else
+		return vga_io_r (port);
+}
+
+static inline void vga_w (void __iomem *regbase, unsigned short port, unsigned char val)
+{
+	if (regbase)
+		vga_mm_w (regbase, port, val);
+	else
+		vga_io_w (port, val);
+}
+
+
+static inline void vga_w_fast (void __iomem *regbase, unsigned short port,
+			       unsigned char reg, unsigned char val)
+{
+	if (regbase)
+		vga_mm_w_fast (regbase, port, reg, val);
+	else
+		vga_io_w_fast (port, reg, val);
+}
+
+
+/*
+ * VGA CRTC register read/write
+ */
+
+static inline unsigned char vga_rcrt (void __iomem *regbase, unsigned char reg)
+{
+        vga_w (regbase, VGA_CRT_IC, reg);
+        return vga_r (regbase, VGA_CRT_DC);
+}
+
+static inline void vga_wcrt (void __iomem *regbase, unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_w_fast (regbase, VGA_CRT_IC, reg, val);
+#else
+        vga_w (regbase, VGA_CRT_IC, reg);
+        vga_w (regbase, VGA_CRT_DC, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+static inline unsigned char vga_io_rcrt (unsigned char reg)
+{
+        vga_io_w (VGA_CRT_IC, reg);
+        return vga_io_r (VGA_CRT_DC);
+}
+
+static inline void vga_io_wcrt (unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_io_w_fast (VGA_CRT_IC, reg, val);
+#else
+        vga_io_w (VGA_CRT_IC, reg);
+        vga_io_w (VGA_CRT_DC, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+static inline unsigned char vga_mm_rcrt (void __iomem *regbase, unsigned char reg)
+{
+        vga_mm_w (regbase, VGA_CRT_IC, reg);
+        return vga_mm_r (regbase, VGA_CRT_DC);
+}
+
+static inline void vga_mm_wcrt (void __iomem *regbase, unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_mm_w_fast (regbase, VGA_CRT_IC, reg, val);
+#else
+        vga_mm_w (regbase, VGA_CRT_IC, reg);
+        vga_mm_w (regbase, VGA_CRT_DC, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+
+/*
+ * VGA sequencer register read/write
+ */
+
+static inline unsigned char vga_rseq (void __iomem *regbase, unsigned char reg)
+{
+        vga_w (regbase, VGA_SEQ_I, reg);
+        return vga_r (regbase, VGA_SEQ_D);
+}
+
+static inline void vga_wseq (void __iomem *regbase, unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_w_fast (regbase, VGA_SEQ_I, reg, val);
+#else
+        vga_w (regbase, VGA_SEQ_I, reg);
+        vga_w (regbase, VGA_SEQ_D, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+static inline unsigned char vga_io_rseq (unsigned char reg)
+{
+        vga_io_w (VGA_SEQ_I, reg);
+        return vga_io_r (VGA_SEQ_D);
+}
+
+static inline void vga_io_wseq (unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_io_w_fast (VGA_SEQ_I, reg, val);
+#else
+        vga_io_w (VGA_SEQ_I, reg);
+        vga_io_w (VGA_SEQ_D, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+static inline unsigned char vga_mm_rseq (void __iomem *regbase, unsigned char reg)
+{
+        vga_mm_w (regbase, VGA_SEQ_I, reg);
+        return vga_mm_r (regbase, VGA_SEQ_D);
+}
+
+static inline void vga_mm_wseq (void __iomem *regbase, unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_mm_w_fast (regbase, VGA_SEQ_I, reg, val);
+#else
+        vga_mm_w (regbase, VGA_SEQ_I, reg);
+        vga_mm_w (regbase, VGA_SEQ_D, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+/*
+ * VGA graphics controller register read/write
+ */
+
+static inline unsigned char vga_rgfx (void __iomem *regbase, unsigned char reg)
+{
+        vga_w (regbase, VGA_GFX_I, reg);
+        return vga_r (regbase, VGA_GFX_D);
+}
+
+static inline void vga_wgfx (void __iomem *regbase, unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_w_fast (regbase, VGA_GFX_I, reg, val);
+#else
+        vga_w (regbase, VGA_GFX_I, reg);
+        vga_w (regbase, VGA_GFX_D, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+static inline unsigned char vga_io_rgfx (unsigned char reg)
+{
+        vga_io_w (VGA_GFX_I, reg);
+        return vga_io_r (VGA_GFX_D);
+}
+
+static inline void vga_io_wgfx (unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_io_w_fast (VGA_GFX_I, reg, val);
+#else
+        vga_io_w (VGA_GFX_I, reg);
+        vga_io_w (VGA_GFX_D, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+static inline unsigned char vga_mm_rgfx (void __iomem *regbase, unsigned char reg)
+{
+        vga_mm_w (regbase, VGA_GFX_I, reg);
+        return vga_mm_r (regbase, VGA_GFX_D);
+}
+
+static inline void vga_mm_wgfx (void __iomem *regbase, unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_mm_w_fast (regbase, VGA_GFX_I, reg, val);
+#else
+        vga_mm_w (regbase, VGA_GFX_I, reg);
+        vga_mm_w (regbase, VGA_GFX_D, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+
+/*
+ * VGA attribute controller register read/write
+ */
+
+static inline unsigned char vga_rattr (void __iomem *regbase, unsigned char reg)
+{
+        vga_w (regbase, VGA_ATT_IW, reg);
+        return vga_r (regbase, VGA_ATT_R);
+}
+
+static inline void vga_wattr (void __iomem *regbase, unsigned char reg, unsigned char val)
+{
+        vga_w (regbase, VGA_ATT_IW, reg);
+        vga_w (regbase, VGA_ATT_W, val);
+}
+
+static inline unsigned char vga_io_rattr (unsigned char reg)
+{
+        vga_io_w (VGA_ATT_IW, reg);
+        return vga_io_r (VGA_ATT_R);
+}
+
+static inline void vga_io_wattr (unsigned char reg, unsigned char val)
+{
+        vga_io_w (VGA_ATT_IW, reg);
+        vga_io_w (VGA_ATT_W, val);
+}
+
+static inline unsigned char vga_mm_rattr (void __iomem *regbase, unsigned char reg)
+{
+        vga_mm_w (regbase, VGA_ATT_IW, reg);
+        return vga_mm_r (regbase, VGA_ATT_R);
+}
+
+static inline void vga_mm_wattr (void __iomem *regbase, unsigned char reg, unsigned char val)
+{
+        vga_mm_w (regbase, VGA_ATT_IW, reg);
+        vga_mm_w (regbase, VGA_ATT_W, val);
+}
+
+#endif /* __linux_video_vga_h__ */
commit 94d7b48334d86b401439d732407d5989557d2218
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Wed Jan 25 16:10:44 2012 +0000

    vga: move Cirrus VGA template to its own file
    
    Standard VGA does not use vga_draw_cursor_line_* functions.
    Move the template to cirrus_vga_template.h.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 116e2b1..a8e8ab7 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2164,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);
diff --git a/hw/cirrus_vga_template.h b/hw/cirrus_vga_template.h
new file mode 100644
index 0000000..3b28280
--- /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/vga_int.h b/hw/vga_int.h
index c1e700f..f755582 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -205,19 +205,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 681425f..7150573 100644
--- a/hw/vga_template.h
+++ b/hw/vga_template.h
@@ -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 */
 
 
commit cd7a45c95ecf2404810f3c6becb7cb83c5010ad8
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Jan 22 16:38:21 2012 +0000

    memory: change dirty getting API to take a size
    
    Instead of each device knowing or guessing the guest page size,
    just pass the desired size of dirtied memory area.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/arch_init.c b/arch_init.c
index 2366511..699bdd1 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -141,7 +141,8 @@ static int ram_save_block(QEMUFile *f)
 
     do {
         mr = block->mr;
-        if (memory_region_get_dirty(mr, offset, DIRTY_MEMORY_MIGRATION)) {
+        if (memory_region_get_dirty(mr, offset, TARGET_PAGE_SIZE,
+                                    DIRTY_MEMORY_MIGRATION)) {
             uint8_t *p;
             int cont = (block == last_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
 
@@ -198,7 +199,7 @@ static ram_addr_t ram_save_remaining(void)
     QLIST_FOREACH(block, &ram_list.blocks, next) {
         ram_addr_t addr;
         for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
-            if (memory_region_get_dirty(block->mr, addr,
+            if (memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
                                         DIRTY_MEMORY_MIGRATION)) {
                 count++;
             }
@@ -283,7 +284,7 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
         /* Make sure all dirty bits are set */
         QLIST_FOREACH(block, &ram_list.blocks, next) {
             for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
-                if (!memory_region_get_dirty(block->mr, addr,
+                if (!memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
                                              DIRTY_MEMORY_MIGRATION)) {
                     memory_region_set_dirty(block->mr, addr, TARGET_PAGE_SIZE);
                 }
diff --git a/exec-obsolete.h b/exec-obsolete.h
index d2749d3..94c23d0 100644
--- a/exec-obsolete.h
+++ b/exec-obsolete.h
@@ -59,10 +59,21 @@ static inline int cpu_physical_memory_get_dirty_flags(ram_addr_t addr)
     return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS];
 }
 
-static inline int cpu_physical_memory_get_dirty(ram_addr_t addr,
+static inline int cpu_physical_memory_get_dirty(ram_addr_t start,
+                                                ram_addr_t length,
                                                 int dirty_flags)
 {
-    return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags;
+    int ret = 0;
+    uint8_t *p;
+    ram_addr_t addr, end;
+
+    end = TARGET_PAGE_ALIGN(start + length);
+    start &= TARGET_PAGE_MASK;
+    p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
+    for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
+        ret |= *p++ & dirty_flags;
+    }
+    return ret;
 }
 
 static inline void cpu_physical_memory_set_dirty(ram_addr_t addr)
diff --git a/hw/framebuffer.c b/hw/framebuffer.c
index 6bf48dc..ea122fb 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/g364fb.c b/hw/g364fb.c
index f47acc5..66d0044 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,
diff --git a/hw/sm501.c b/hw/sm501.c
index 09c5894..94c0abf 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/tcx.c b/hw/tcx.c
index f400f92..ceb94c7 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -178,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;
 }
 
@@ -245,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)
diff --git a/hw/vga.c b/hw/vga.c
index 4dc2610..cf9b39f 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1742,17 +1742,10 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
         if (!(s->cr[0x17] & 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) {
@@ -1798,7 +1791,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);
diff --git a/memory.c b/memory.c
index ee4c98a..5e77d8a 100644
--- a/memory.c
+++ b/memory.c
@@ -1136,10 +1136,11 @@ void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
 }
 
 bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
-                             unsigned client)
+                             target_phys_addr_t size, unsigned client)
 {
     assert(mr->terminates);
-    return cpu_physical_memory_get_dirty(mr->ram_addr + addr, 1 << client);
+    return cpu_physical_memory_get_dirty(mr->ram_addr + addr, size,
+                                         1 << client);
 }
 
 void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr,
diff --git a/memory.h b/memory.h
index fa45b99..4cf8d2f 100644
--- a/memory.h
+++ b/memory.h
@@ -380,20 +380,21 @@ void memory_region_set_offset(MemoryRegion *mr, target_phys_addr_t offset);
 void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client);
 
 /**
- * memory_region_get_dirty: Check whether a page is dirty for a specified
- *                          client.
+ * memory_region_get_dirty: Check whether a range of bytes is dirty
+ *                          for a specified client.
  *
- * Checks whether a page has been written to since the last
+ * Checks whether a range of bytes has been written to since the last
  * call to memory_region_reset_dirty() with the same @client.  Dirty logging
  * must be enabled.
  *
  * @mr: the memory region being queried.
  * @addr: the address (relative to the start of the region) being queried.
+ * @size: the size of the range being queried.
  * @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or
  *          %DIRTY_MEMORY_VGA.
  */
 bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
-                             unsigned client);
+                             target_phys_addr_t size, unsigned client);
 
 /**
  * memory_region_set_dirty: Mark a range of bytes as dirty in a memory region.
commit cb437e48ab7ddd9b85843beb524904ee4b565721
Merge: 2944e4e... f78b0f0...
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Feb 4 12:18:36 2012 +0000

    Merge branch 'linux-user-for-upstream' of git://git.linaro.org/people/rikuvoipio/qemu
    
    * 'linux-user-for-upstream' of git://git.linaro.org/people/rikuvoipio/qemu:
      linux-user: Fix sa_flags byte swaps for mips
      linux-user: Define TARGET_QEMU_ESIGRETURN for mips64
      linux-user: Define TARGET_QEMU_ESIGRETURN for mipsn32
      linux-user: Add default configs for mips64[el]
      linux-user: Add default-configs for mipsn32[el]
      linux-user: Implement *listxattr syscalls
      linux-user/syscall.c: Implement f and l versions of set/get/removexattr
      linux-user: Allow NULL value pointer in setxattr and getxattr
      linux-user: fix wait* syscall status returns
      linux-user/strace.c: Correct errno printing for mmap etc
      linux-user: fix QEMU_STRACE=1 segfault
      linux-user: add SO_PEERCRED support for getsockopt
      linux-user/main.c: Add option to user-mode emulation so that user can specify log file name
      linux-user: fake /proc/self/auxv
      linux-user: fake /proc/self/stat
      linux-user: fake /proc/self/maps
      linux-user: add open() hijack infrastructure
      linux-user: save auxv length
      linux-user: stack_base is now mandatory on all targets

commit 2944e4ece235c74dcce3aa11c456f3645ae594fc
Author: Stefan Weil <sw at weilnetz.de>
Date:   Sat Feb 4 09:24:46 2012 +0100

    w32: Fix build with new net bridge code
    
    Commit a7c36ee4920ea3acc227a0248dd161693f207357 added code for a net
    bridge and explicitly said that "this is very Linux centric".
    
    Indeed, compilation failed for w32, so the bridge code is now
    conditional. Hosts which don't support it can simply remove the
    definition of CONFIG_NET_BRIDGE.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/net.c b/net.c
index 1944539..c34474f 100644
--- a/net.c
+++ b/net.c
@@ -38,6 +38,11 @@
 #include "hw/qdev.h"
 #include "iov.h"
 
+/* Net bridge is currently not supported for W32. */
+#if !defined(_WIN32)
+# define CONFIG_NET_BRIDGE
+#endif
+
 static QTAILQ_HEAD(, VLANState) vlans;
 static QTAILQ_HEAD(, VLANClientState) non_vlan_clients;
 
@@ -952,10 +957,12 @@ static const struct {
                 .type = QEMU_OPT_STRING,
                 .help = "script to shut down the interface",
             }, {
+#ifdef CONFIG_NET_BRIDGE
                 .name = "helper",
                 .type = QEMU_OPT_STRING,
                 .help = "command to execute to configure bridge",
             }, {
+#endif
                 .name = "sndbuf",
                 .type = QEMU_OPT_SIZE,
                 .help = "send buffer limit"
@@ -1057,6 +1064,7 @@ static const struct {
             { /* end of list */ }
         },
     },
+#ifdef CONFIG_NET_BRIDGE
     [NET_CLIENT_TYPE_BRIDGE] = {
         .type = "bridge",
         .init = net_init_bridge,
@@ -1074,6 +1082,7 @@ static const struct {
             { /* end of list */ }
         },
     },
+#endif /* CONFIG_NET_BRIDGE */
 };
 
 int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
@@ -1090,14 +1099,16 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
 
     if (is_netdev) {
         if (strcmp(type, "tap") != 0 &&
+#ifdef CONFIG_NET_BRIDGE
+            strcmp(type, "bridge") != 0 &&
+#endif
 #ifdef CONFIG_SLIRP
             strcmp(type, "user") != 0 &&
 #endif
 #ifdef CONFIG_VDE
             strcmp(type, "vde") != 0 &&
 #endif
-            strcmp(type, "socket") != 0 &&
-            strcmp(type, "bridge") != 0) {
+            strcmp(type, "socket") != 0) {
             qerror_report(QERR_INVALID_PARAMETER_VALUE, "type",
                           "a netdev backend type");
             return -1;
@@ -1161,13 +1172,15 @@ static int net_host_check_device(const char *device)
 {
     int i;
     const char *valid_param_list[] = { "tap", "socket", "dump"
+#ifdef CONFIG_NET_BRIDGE
+                                       , "bridge"
+#endif
 #ifdef CONFIG_SLIRP
                                        ,"user"
 #endif
 #ifdef CONFIG_VDE
                                        ,"vde"
 #endif
-                                       , "bridge"
     };
     for (i = 0; i < sizeof(valid_param_list) / sizeof(char *); i++) {
         if (!strncmp(valid_param_list[i], device,
commit f0c4d3ebc31969457850a710c25e663880072ed7
Merge: c9344f2... a496e8e...
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Feb 4 09:37:55 2012 +0000

    Merge branch 'for-upstream' of git://repo.or.cz/qemu/agraf
    
    * 'for-upstream' of git://repo.or.cz/qemu/agraf: (21 commits)
      PPC: E500: Populate L1CFG0 SPR
      PPC: e500mc: Enable processor control
      PPC: E500: Implement msgsnd
      PPC: E500: Implement msgclr
      PPC: Enable doorbell excp handlers
      PPC: Add CPU feature for processor control
      PPC: E500: Add doorbell defines
      PPC: E500: Add some more excp vectors
      KVM: Fix compilation on non-x86
      PPC: booke206: move avail check to tlbwe
      PPC: booke206: Check for TLB overrun
      PPC: booke206: Implement tlbilx
      PPC: booke206: Check for min/max TLB entry size
      PPC: booke: add tlbnps handling
      PPC: booke206: allow NULL raddr in ppcmas_tlb_check
      PPC: rename msync to msync_4xx
      PPC: e500: msync is 440 only, e500 has real sync
      PPC: e500mc: add missing IVORs to bitmap
      PPC: Add IVOR 38-42
      PPC: KVM: Update HIOR code to new interface
      ...

commit c9344f2220ec9878493af5a39b7f0f337e58123a
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Feb 3 11:22:35 2012 -0600

    Fix build breakage from last commit.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/blockdev.c b/blockdev.c
index 7d7ac31..7a6613a 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -18,6 +18,7 @@
 #include "block_int.h"
 #include "qmp-commands.h"
 #include "trace.h"
+#include "arch_init.h"
 
 static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
 
commit eeb9c1b552c7e30d6fc10e8c5ccab4b0ea4826c0
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Feb 3 11:13:30 2012 -0600

    s390x: fix -drive in the absence of aliases
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/blockdev.c b/blockdev.c
index 7e4c548..7d7ac31 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -565,7 +565,11 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
     case IF_VIRTIO:
         /* add virtio block device */
         opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
-        qemu_opt_set(opts, "driver", "virtio-blk");
+        if (arch_type == QEMU_ARCH_S390X) {
+            qemu_opt_set(opts, "driver", "virtio-blk-s390");
+        } else {
+            qemu_opt_set(opts, "driver", "virtio-blk-pci");
+        }
         qemu_opt_set(opts, "drive", dinfo->id);
         if (devaddr)
             qemu_opt_set(opts, "addr", devaddr);
commit 8b45d447ce5cce07cbdf0f42b969137430284d5c
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 23 09:08:05 2011 -0600

    container: make a decendent of Object
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    ---
    v1 -> v2
     - Add license (Paolo)

diff --git a/Makefile.objs b/Makefile.objs
index 1a26349..ec35320 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -286,7 +286,7 @@ hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
 hw-obj-$(CONFIG_ESP) += esp.o
 
 hw-obj-y += dma-helpers.o sysbus.o isa-bus.o
-hw-obj-y += qdev-addr.o container.o
+hw-obj-y += qdev-addr.o
 
 # VGA
 hw-obj-$(CONFIG_VGA_PCI) += vga-pci.o
diff --git a/hw/container.c b/hw/container.c
deleted file mode 100644
index 1e97031..0000000
--- a/hw/container.c
+++ /dev/null
@@ -1,29 +0,0 @@
-#include "sysbus.h"
-
-static int container_initfn(SysBusDevice *dev)
-{
-    return 0;
-}
-
-static void container_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = container_initfn;
-    dc->no_user = 1;
-}
-
-static TypeInfo container_info = {
-    .name          = "container",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SysBusDevice),
-    .class_init    = container_class_init,
-};
-
-static void container_init(void)
-{
-    type_register_static(&container_info);
-}
-
-device_init(container_init);
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index 56a3458..135c2bf 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -177,30 +177,28 @@ int qdev_device_help(QemuOpts *opts)
 
 static Object *qdev_get_peripheral(void)
 {
-    static DeviceState *dev;
+    static Object *dev;
 
     if (dev == NULL) {
-        dev = qdev_create(NULL, "container");
+        dev = object_new("container");
         object_property_add_child(object_get_root(), "peripheral",
                                   OBJECT(dev), NULL);
-        qdev_init_nofail(dev);
     }
 
-    return OBJECT(dev);
+    return dev;
 }
 
 static Object *qdev_get_peripheral_anon(void)
 {
-    static DeviceState *dev;
+    static Object *dev;
 
     if (dev == NULL) {
-        dev = qdev_create(NULL, "container");
+        dev = object_new("container");
         object_property_add_child(object_get_root(), "peripheral-anon",
                                   OBJECT(dev), NULL);
-        qdev_init_nofail(dev);
     }
 
-    return OBJECT(dev);
+    return dev;
 }
 
 static void qbus_list_bus(DeviceState *dev)
diff --git a/qom/Makefile b/qom/Makefile
index a3c7892..f33f0be 100644
--- a/qom/Makefile
+++ b/qom/Makefile
@@ -1 +1 @@
-qom-y = object.o
+qom-y = object.o container.o
diff --git a/qom/container.c b/qom/container.c
new file mode 100644
index 0000000..946cbff
--- /dev/null
+++ b/qom/container.c
@@ -0,0 +1,27 @@
+/*
+ * Device Container
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/object.h"
+#include "module.h"
+
+static TypeInfo container_info = {
+    .name          = "container",
+    .instance_size = sizeof(Object),
+    .parent        = TYPE_OBJECT,
+};
+
+static void container_init(void)
+{
+    type_register_static(&container_info);
+}
+
+device_init(container_init);
diff --git a/qom/object.c b/qom/object.c
index 33217b8..4261944 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -662,14 +662,13 @@ const char *object_property_get_type(Object *obj, const char *name, Error **errp
 
 Object *object_get_root(void)
 {
-    static DeviceState *object_root;
+    static Object *root;
 
-    if (!object_root) {
-        object_root = qdev_create(NULL, "container");
-        qdev_init_nofail(object_root);
+    if (!root) {
+        root = object_new("container");
     }
 
-    return OBJECT(object_root);
+    return root;
 }
 
 static void object_get_child_property(Object *obj, Visitor *v, void *opaque,
commit db85b575b9f29487d1dd854da730a9293d91198a
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 23 08:47:39 2011 -0600

    object: sure up reference counting
    
    Now we have the following behavior:
    
    1) object_new() returns an object with ref = 1
    2) object_initialize() does not increase the reference count (ref may be 0).
    3) object_deref() will finalize the object when ref = 0.  it does not free the
       memory associated with the object.
    4) both link and child properties correctly set the reference count.
    
    The expected usage is the following:
    
    1) child devices should generally be created via object_initialize() using
       memory from the parent device.  Adding the object as a child property will
       take ownership of the object and tie the child's life cycle to the parent.
    
    2) If a child device is created via qdev_create() or some other form of
       object_new(), there must be an object_delete() call in the parent device's
       finalize function.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/qom/object.c b/qom/object.c
index 49addef..33217b8 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -337,6 +337,8 @@ void object_finalize(void *data)
 
     object_deinit(obj, ti);
     object_property_del_all(obj);
+
+    g_assert(obj->ref == 0);
 }
 
 Object *object_new_with_type(Type type)
@@ -347,6 +349,7 @@ Object *object_new_with_type(Type type)
 
     obj = g_malloc(type->instance_size);
     object_initialize_with_type(obj, type);
+    object_ref(obj);
 
     return obj;
 }
@@ -360,7 +363,8 @@ Object *object_new(const char *typename)
 
 void object_delete(Object *obj)
 {
-    object_finalize(obj);
+    object_unref(obj);
+    g_assert(obj->ref == 0);
     g_free(obj);
 }
 
@@ -679,6 +683,14 @@ static void object_get_child_property(Object *obj, Visitor *v, void *opaque,
     g_free(path);
 }
 
+static void object_finalize_child_property(Object *obj, const char *name,
+                                           void *opaque)
+{
+    Object *child = opaque;
+
+    object_unref(child);
+}
+
 void object_property_add_child(Object *obj, const char *name,
                                Object *child, Error **errp)
 {
@@ -687,7 +699,7 @@ void object_property_add_child(Object *obj, const char *name,
     type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
 
     object_property_add(obj, name, type, object_get_child_property,
-                        NULL, NULL, child, errp);
+                        NULL, object_finalize_child_property, child, errp);
 
     object_ref(child);
     g_assert(child->parent == NULL);
commit d03d6b4e5cc33d5c9e035e68aa30da1a32780f7d
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 23 08:16:58 2011 -0600

    info qdm: do not require a parent_bus to be set
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index a6f0e16..56a3458 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -163,12 +163,14 @@ int qdev_device_help(QemuOpts *opts)
         error_printf("%s.%s=%s\n", driver, 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 */
+    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);
         }
-        error_printf("%s.%s=%s\n", driver, prop->name,
-                     prop->info->legacy_name ?: prop->info->name);
     }
     return 1;
 }
commit 60adba3769e8430e57e3a3e651f8041efdd7488e
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 23 08:38:56 2011 -0600

    qdev: implement cleanup logic in finalize
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev.c b/hw/qdev.c
index 8f13e49..e3b53b7 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -247,31 +247,6 @@ void qdev_init_nofail(DeviceState *dev)
 /* Unlink device from bus and free the structure.  */
 void qdev_free(DeviceState *dev)
 {
-    BusState *bus;
-    Property *prop;
-    DeviceClass *dc = DEVICE_GET_CLASS(dev);
-
-    if (dev->state == DEV_STATE_INITIALIZED) {
-        while (dev->num_child_bus) {
-            bus = QLIST_FIRST(&dev->child_bus);
-            qbus_free(bus);
-        }
-        if (qdev_get_vmsd(dev)) {
-            vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
-        }
-        if (dc->exit) {
-            dc->exit(dev);
-        }
-        if (dev->opts) {
-            qemu_opts_del(dev->opts);
-        }
-    }
-    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);
-        }
-    }
     object_delete(OBJECT(dev));
 }
 
@@ -634,6 +609,37 @@ static void device_initfn(Object *obj)
     object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL);
 }
 
+/* Unlink device from bus and free the structure.  */
+static void device_finalize(Object *obj)
+{
+    DeviceState *dev = DEVICE(obj);
+    BusState *bus;
+    Property *prop;
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
+    if (dev->state == DEV_STATE_INITIALIZED) {
+        while (dev->num_child_bus) {
+            bus = QLIST_FIRST(&dev->child_bus);
+            qbus_free(bus);
+        }
+        if (qdev_get_vmsd(dev)) {
+            vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
+        }
+        if (dc->exit) {
+            dc->exit(dev);
+        }
+        if (dev->opts) {
+            qemu_opts_del(dev->opts);
+        }
+    }
+    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);
+        }
+    }
+}
+
 void device_reset(DeviceState *dev)
 {
     DeviceClass *klass = DEVICE_GET_CLASS(dev);
@@ -648,6 +654,7 @@ static TypeInfo device_type_info = {
     .parent = TYPE_OBJECT,
     .instance_size = sizeof(DeviceState),
     .instance_init = device_initfn,
+    .instance_finalize = device_finalize,
     .abstract = true,
     .class_size = sizeof(DeviceClass),
 };
commit fe40e627c51e38922b64b02b6163aea4b6aad896
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 23 08:35:43 2011 -0600

    qom: accept any compatible type when setting a link property
    
    Links had limited utility before as they only allowed a concrete type to be
    specified.  Now we can support abstract types and interfaces which means it's
    now possible to have a link<PCIDevice>.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/qom/object.c b/qom/object.c
index 2506d78..49addef 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -735,11 +735,12 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
         if (target) {
             gchar *target_type;
 
-            target_type = g_strdup_printf("link<%s>",
-                                          object_get_typename(OBJECT(target)));
-            if (strcmp(target_type, type) == 0) {
-                *child = target;
+            target_type = g_strdup(&type[5]);
+            target_type[strlen(target_type) - 2] = 0;
+
+            if (object_dynamic_cast(target, target_type)) {
                 object_ref(target);
+                *child = target;
             } else {
                 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
             }
commit 57c9fafe0f759c9f1efa5451662b3627f9bb95e0
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Jan 30 08:55:55 2012 -0600

    qom: move properties from qdev to object
    
    This is mostly code movement although not entirely.  This makes properties part
    of the Object base class which means that we can now start using Object in a
    meaningful way outside of qdev.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index cbbf1f0..4a43225 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -628,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 = ISA_DEVICE(dev);
+    ISADevice *isa = ISA_DEVICE(obj);
     RTCState *s = DO_UPCAST(RTCState, dev, isa);
 
     visit_start_struct(v, NULL, "struct tm", name, 0, errp);
@@ -686,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;
 }
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index a285ad2..c06f1b5 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -229,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()) {
@@ -267,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 1df05ae..5f4f80e 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1517,6 +1517,7 @@ static int pci_unplug_device(DeviceState *qdev)
         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);
 }
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 2bbfa4a..1906427 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"));
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index ff9594e..eb43fb5 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -610,7 +610,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
     pcihost = DO_UPCAST(PCIHostState, busdev, sys);
     pcihost->address_space = get_system_memory();
     qdev_init_nofail(dev);
-    qdev_property_add_child(qdev_get_root(), "raven", DEVICE(dev), NULL);
+    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");
diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c
index 5ddda2d..5976dcd 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
index 841e1ad..a6f0e16 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -173,30 +173,32 @@ int qdev_device_help(QemuOpts *opts)
     return 1;
 }
 
-static DeviceState *qdev_get_peripheral(void)
+static Object *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);
+        object_property_add_child(object_get_root(), "peripheral",
+                                  OBJECT(dev), NULL);
         qdev_init_nofail(dev);
     }
 
-    return dev;
+    return OBJECT(dev);
 }
 
-static DeviceState *qdev_get_peripheral_anon(void)
+static Object *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);
+        object_property_add_child(object_get_root(), "peripheral-anon",
+                                  OBJECT(dev), NULL);
         qdev_init_nofail(dev);
     }
 
-    return dev;
+    return OBJECT(dev);
 }
 
 static void qbus_list_bus(DeviceState *dev)
@@ -455,12 +457,13 @@ DeviceState *qdev_device_add(QemuOpts *opts)
     id = qemu_opts_id(opts);
     if (id) {
         qdev->id = id;
-        qdev_property_add_child(qdev_get_peripheral(), qdev->id, qdev, NULL);
+        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++);
-        qdev_property_add_child(qdev_get_peripheral_anon(), name,
-                                qdev, NULL);
+        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) {
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 2e3ef70..c4583a1 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -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;
@@ -971,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];
diff --git a/hw/qdev.c b/hw/qdev.c
index 0692a21..8f13e49 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -222,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;
 }
@@ -243,46 +244,6 @@ void qdev_init_nofail(DeviceState *dev)
     }
 }
 
-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)
 {
@@ -290,8 +251,6 @@ void qdev_free(DeviceState *dev)
     Property *prop;
     DeviceClass *dc = DEVICE_GET_CLASS(dev);
 
-    qdev_property_del_all(dev);
-
     if (dev->state == DEV_STATE_INITIALIZED) {
         while (dev->num_child_bus) {
             bus = QLIST_FIRST(&dev->child_bus);
@@ -313,12 +272,6 @@ void qdev_free(DeviceState *dev)
             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?:"");
-    }
     object_delete(OBJECT(dev));
 }
 
@@ -569,106 +522,19 @@ char* qdev_get_fw_dev_path(DeviceState *dev)
     return strdup(path);
 }
 
-char *qdev_get_type(DeviceState *dev, Error **errp)
-{
-    return g_strdup(object_get_typename(OBJECT(dev)));
-}
-
-void qdev_ref(DeviceState *dev)
+static char *qdev_get_type(Object *obj, Error **errp)
 {
-    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];
@@ -678,9 +544,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;
@@ -720,11 +587,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);
@@ -739,333 +606,10 @@ 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);
-}
-
-static void qdev_release_child_property(DeviceState *dev, const char *name,
-                                        void *opaque)
-{
-    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>", object_get_typename(OBJECT(child)));
-
-    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>", object_get_typename(OBJECT(target)));
-            if (strcmp(target_type, type) == 0) {
-                *child = target;
-                qdev_ref(target);
-            } else {
-                error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
-            }
-
-            g_free(target_type);
-        } else {
-            error_set(errp, QERR_DEVICE_NOT_FOUND, path);
-        }
-    } else {
-        *child = NULL;
-    }
-
-    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 = dev->parent;
-    }
-
-    newpath = g_strdup_printf("/%s", path);
-    g_free(path);
-
-    return newpath;
-}
-
-static DeviceState *qdev_resolve_abs_path(DeviceState *parent,
-                                          gchar **parts,
-                                          int index)
-{
-    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;
-    }
-
-    child = NULL;
-    if (strstart(prop->type, "link<", NULL)) {
-        DeviceState **pchild = prop->opaque;
-        if (*pchild) {
-            child = *pchild;
-        }
-    } 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;
-        }
-
-        found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous);
-        if (found) {
-            if (dev) {
-                if (ambiguous) {
-                    *ambiguous = true;
-                }
-                return NULL;
-            }
-            dev = found;
-        }
-
-        if (ambiguous && *ambiguous) {
-            return NULL;
-        }
-    }
-
-    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;
-        }
-        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)
-{
-    StringProperty *prop = opaque;
-    char *value;
-    Error *local_err = NULL;
-
-    visit_type_str(v, &value, name, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        return;
-    }
-
-    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);
-}
-
-void qdev_property_add_str(DeviceState *dev, const char *name,
-                           char *(*get)(DeviceState *, Error **),
-                           void (*set)(DeviceState *, const char *, Error **),
-                           Error **errp)
-{
-    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);
+    object_property_add(OBJECT(dev), prop->name, prop->info->name,
+                        prop->info->get, prop->info->set,
+                        NULL,
+                        prop, errp);
 }
 
 static void device_initfn(Object *obj)
@@ -1079,7 +623,6 @@ static void device_initfn(Object *obj)
     }
 
     dev->instance_id_alias = -1;
-    QTAILQ_INIT(&dev->properties);
     dev->state = DEV_STATE_CREATED;
 
     qdev_prop_set_defaults(dev, qdev_get_props(dev));
@@ -1088,7 +631,7 @@ static void device_initfn(Object *obj)
         qdev_property_add_static(dev, prop, NULL);
     }
 
-    qdev_property_add_str(dev, "type", qdev_get_type, NULL, NULL);
+    object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL);
 }
 
 void device_reset(DeviceState *dev)
diff --git a/hw/qdev.h b/hw/qdev.h
index 8f525ec..ab53273 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -27,44 +27,6 @@ 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);
-
-/**
- * @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;
-
 #define TYPE_DEVICE "device"
 #define DEVICE(obj) OBJECT_CHECK(DeviceState, (obj), TYPE_DEVICE)
 #define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE)
@@ -114,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);
@@ -195,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 {
@@ -390,235 +340,12 @@ char *qdev_get_fw_dev_path(DeviceState *dev);
 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
- *
- * Returns:
- *   The root of the composition tree.
- */
-DeviceState *qdev_get_root(void);
-
-/**
- * @qdev_get_canonical_path - returns the canonical path for a device.  This
- * is the path within the composition tree starting from the root.
- *
- * Returns:
- *   The canonical path in the composition tree.
- */
-gchar *qdev_get_canonical_path(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);
-
-/**
- * @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);
-
-/**
- * @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);
-
-/**
- * @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);
-
-/**
- * @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);
-
-/**
  * @qdev_machine_init
  *
  * Initialize platform devices before machine init.  This is a hack until full
diff --git a/include/qemu/object.h b/include/qemu/object.h
index a20271f..9d0251d 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -17,6 +17,10 @@
 #include <glib.h>
 #include <stdint.h>
 #include <stdbool.h>
+#include "qemu-queue.h"
+
+struct Visitor;
+struct Error;
 
 struct TypeImpl;
 typedef struct TypeImpl *Type;
@@ -114,6 +118,47 @@ typedef struct InterfaceInfo InterfaceInfo;
  * to one of its #Interface types and vice versa.
  */
 
+
+/**
+ * ObjectPropertyAccessor:
+ * @obj: the object that owns the property
+ * @v: the visitor that contains the property data
+ * @opaque: the object property opaque
+ * @name: the name of the property
+ * @errp: a pointer to an Error that is filled if getting/setting fails.
+ *
+ * Called when trying to get/set a property.
+ */
+typedef void (ObjectPropertyAccessor)(Object *obj,
+                                      struct Visitor *v,
+                                      void *opaque,
+                                      const char *name,
+                                      struct Error **errp);
+
+/**
+ * ObjectPropertyRelease:
+ * @obj: the object that owns the property
+ * @name: the name of the property
+ * @opaque: the opaque registered with the property
+ *
+ * Called when a property is removed from a object.
+ */
+typedef void (ObjectPropertyRelease)(Object *obj,
+                                     const char *name,
+                                     void *opaque);
+
+typedef struct ObjectProperty
+{
+    gchar *name;
+    gchar *type;
+    ObjectPropertyAccessor *get;
+    ObjectPropertyAccessor *set;
+    ObjectPropertyRelease *release;
+    void *opaque;
+
+    QTAILQ_ENTRY(ObjectProperty) node;
+} ObjectProperty;
+
 /**
  * ObjectClass:
  *
@@ -145,8 +190,10 @@ struct Object
 {
     /*< private >*/
     ObjectClass *class;
-
     GSList *interfaces;
+    QTAILQ_HEAD(, ObjectProperty) properties;
+    uint32_t ref;
+    Object *parent;
 };
 
 /**
@@ -435,5 +482,181 @@ ObjectClass *object_class_by_name(const char *typename);
 void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
                           const char *implements_type, bool include_abstract,
                           void *opaque);
+/**
+ * object_ref:
+ * @obj: the object
+ *
+ * Increase the reference count of a object.  A object cannot be freed as long
+ * as its reference count is greater than zero.
+ */
+void object_ref(Object *obj);
+
+/**
+ * qdef_unref:
+ * @obj: the object
+ *
+ * Decrease the reference count of a object.  A object cannot be freed as long
+ * as its reference count is greater than zero.
+ */
+void object_unref(Object *obj);
+
+/**
+ * object_property_add:
+ * @obj: the object 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 object.  This is
+ *   meant to allow a property to free its opaque upon object
+ *   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 object_property_add(Object *obj, const char *name, const char *type,
+                         ObjectPropertyAccessor *get,
+                         ObjectPropertyAccessor *set,
+                         ObjectPropertyRelease *release,
+                         void *opaque, struct Error **errp);
+
+void object_property_del(Object *obj, const char *name, struct Error **errp);
+
+void object_unparent(Object *obj);
+
+/**
+ * object_property_get:
+ * @obj: the object
+ * @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
+ *
+ * Reads a property from a object.
+ */
+void object_property_get(Object *obj, struct Visitor *v, const char *name,
+                         struct Error **errp);
+
+/**
+ * object_property_set:
+ * @obj: the object
+ * @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
+ *
+ * Writes a property to a object.
+ */
+void object_property_set(Object *obj, struct Visitor *v, const char *name,
+                         struct Error **errp);
+
+/**
+ * @object_property_get_type:
+ * @obj: the object
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Returns:  The type name of the property.
+ */
+const char *object_property_get_type(Object *obj, const char *name,
+                                     struct Error **errp);
+
+/**
+ * object_get_root:
+ *
+ * Returns: the root object of the composition tree
+ */
+Object *object_get_root(void);
+
+/**
+ * object_get_canonical_path:
+ *
+ * Returns: The canonical path for a object.  This is the path within the
+ * composition tree starting from the root.
+ */
+gchar *object_get_canonical_path(Object *obj);
+
+/**
+ * object_resolve_path:
+ * @path: the path to resolve
+ * @ambiguous: returns true if the path resolution failed because of an
+ *   ambiguous match
+ *
+ * There are two types of supported paths--absolute paths and partial paths.
+ * 
+ * Absolute paths are derived from the root object 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 objects 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.
+ *
+ * Returns: The matched object or NULL on path lookup failure.
+ */
+Object *object_resolve_path(const char *path, bool *ambiguous);
+
+/**
+ * object_property_add_child:
+ * @obj: the object to add a property to
+ * @name: the name of the property
+ * @child: the child object
+ * @errp: if an error occurs, a pointer to an area to store the area
+ *
+ * Child properties form the composition tree.  All objects need to be a child
+ * of another object.  Objects can only be a child of one object.
+ *
+ * There is no way for a child to determine what its parent is.  It is not
+ * a bidirectional relationship.  This is by design.
+ */
+void object_property_add_child(Object *obj, const char *name,
+                               Object *child, struct Error **errp);
+
+/**
+ * object_property_add_link:
+ * @obj: the object to add a property to
+ * @name: the name of the property
+ * @type: the qobj type of the link
+ * @child: a pointer to where the link object reference is stored
+ * @errp: if an error occurs, a pointer to an area to store the area
+ *
+ * Links establish relationships between objects.  Links are unidirectional
+ * although two links can be combined to form a bidirectional relationship
+ * between objects.
+ *
+ * Links form the graph in the object model.
+ */
+void object_property_add_link(Object *obj, const char *name,
+                              const char *type, Object **child,
+                              struct Error **errp);
+
+/**
+ * object_property_add_str:
+ * @obj: the object 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
+ *
+ * Add a string property using getters/setters.  This function will add a
+ * property of type 'string'.
+ */
+void object_property_add_str(Object *obj, const char *name,
+                             char *(*get)(Object *, struct Error **),
+                             void (*set)(Object *, const char *, struct Error **),
+                             struct Error **errp);
 
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index 56a4123..d02ee86 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1228,20 +1228,20 @@
 #
 # Notes: This type is experimental.  Its syntax may change in future releases.
 ##
-{ 'type': 'DevicePropertyInfo',
+{ 'type': 'ObjectPropertyInfo',
   'data': { 'name': 'str', 'type': 'str' } }
 
 ##
 # @qom-list:
 #
-# This command will list any properties of a device given a path in the device
+# This command will list any properties of a object given a path in the object
 # model.
 #
-# @path: the path within the device model.  See @qom-get for a description of
+# @path: the path within the object model.  See @qom-get for a description of
 #        this parameter.
 #
-# Returns: a list of @DevicePropertyInfo that describe the properties of the
-#          device.
+# Returns: a list of @ObjectPropertyInfo that describe the properties of the
+#          object.
 #
 # Since: 1.1
 #
@@ -1250,25 +1250,25 @@
 ##
 { 'command': 'qom-list',
   'data': { 'path': 'str' },
-  'returns': [ 'DevicePropertyInfo' ] }
+  'returns': [ 'ObjectPropertyInfo' ] }
 
 ##
 # @qom-get:
 #
-# This command will get a property from a device model path and return the
+# This command will get a property from a object model path and return the
 # value.
 #
-# @path: The path within the device model.  There are two forms of supported
+# @path: The path within the object model.  There are two forms of supported
 #        paths--absolute and partial paths.
 #
-#        Absolute paths are derived from the root device and can follow child<>
+#        Absolute paths are derived from the root object 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
+#        designed to make specifying objects 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
@@ -1294,7 +1294,7 @@
 ##
 # @qom-set:
 #
-# This command will set a property from a device model path.
+# This command will set a property from a object model path.
 #
 # @path: see @qom-get for a description of this parameter
 #
diff --git a/qmp.c b/qmp.c
index 75049ed..45052cc 100644
--- a/qmp.c
+++ b/qmp.c
@@ -164,23 +164,23 @@ void qmp_cont(Error **errp)
     vm_start();
 }
 
-DevicePropertyInfoList *qmp_qom_list(const char *path, Error **errp)
+ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
 {
-    DeviceState *dev;
+    Object *obj;
     bool ambiguous = false;
-    DevicePropertyInfoList *props = NULL;
-    DeviceProperty *prop;
+    ObjectPropertyInfoList *props = NULL;
+    ObjectProperty *prop;
 
-    dev = qdev_resolve_path(path, &ambiguous);
-    if (dev == NULL) {
+    obj = object_resolve_path(path, &ambiguous);
+    if (obj == NULL) {
         error_set(errp, QERR_DEVICE_NOT_FOUND, path);
         return NULL;
     }
 
-    QTAILQ_FOREACH(prop, &dev->properties, node) {
-        DevicePropertyInfoList *entry = g_malloc0(sizeof(*entry));
+    QTAILQ_FOREACH(prop, &obj->properties, node) {
+        ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry));
 
-        entry->value = g_malloc0(sizeof(DevicePropertyInfo));
+        entry->value = g_malloc0(sizeof(ObjectPropertyInfo));
         entry->next = props;
         props = entry;
 
@@ -199,16 +199,16 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret)
     QObject *value = qdict_get(qdict, "value");
     Error *local_err = NULL;
     QmpInputVisitor *mi;
-    DeviceState *dev;
+    Object *obj;
 
-    dev = qdev_resolve_path(path, NULL);
-    if (!dev) {
+    obj = object_resolve_path(path, NULL);
+    if (!obj) {
         error_set(&local_err, QERR_DEVICE_NOT_FOUND, path);
         goto out;
     }
 
     mi = qmp_input_visitor_new(value);
-    qdev_property_set(dev, qmp_input_get_visitor(mi), property, &local_err);
+    object_property_set(obj, qmp_input_get_visitor(mi), property, &local_err);
 
     qmp_input_visitor_cleanup(mi);
 
@@ -228,16 +228,16 @@ int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret)
     const char *property = qdict_get_str(qdict, "property");
     Error *local_err = NULL;
     QmpOutputVisitor *mo;
-    DeviceState *dev;
+    Object *obj;
 
-    dev = qdev_resolve_path(path, NULL);
-    if (!dev) {
+    obj = object_resolve_path(path, NULL);
+    if (!obj) {
         error_set(&local_err, QERR_DEVICE_NOT_FOUND, path);
         goto out;
     }
 
     mo = qmp_output_visitor_new();
-    qdev_property_get(dev, qmp_output_get_visitor(mo), property, &local_err);
+    object_property_get(obj, qmp_output_get_visitor(mo), property, &local_err);
     if (!local_err) {
         *ret = qmp_output_get_qobject(mo);
     }
diff --git a/qom/object.c b/qom/object.c
index 3dabb1a..2506d78 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -12,6 +12,9 @@
 
 #include "qemu/object.h"
 #include "qemu-common.h"
+#include "qapi/qapi-visit-core.h"
+#include "hw/qdev.h"
+// FIXME remove above
 
 #define MAX_INTERFACES 32
 
@@ -258,6 +261,7 @@ void object_initialize_with_type(void *data, TypeImpl *type)
 
     memset(obj, 0, type->instance_size);
     obj->class = type->class;
+    QTAILQ_INIT(&obj->properties);
     object_init_with_type(obj, type);
 }
 
@@ -268,6 +272,45 @@ void object_initialize(void *data, const char *typename)
     object_initialize_with_type(data, type);
 }
 
+static void object_property_del_all(Object *obj)
+{
+    while (!QTAILQ_EMPTY(&obj->properties)) {
+        ObjectProperty *prop = QTAILQ_FIRST(&obj->properties);
+
+        QTAILQ_REMOVE(&obj->properties, prop, node);
+
+        if (prop->release) {
+            prop->release(obj, prop->name, prop->opaque);
+        }
+
+        g_free(prop->name);
+        g_free(prop->type);
+        g_free(prop);
+    }
+}
+
+static void object_property_del_child(Object *obj, Object *child, Error **errp)
+{
+    ObjectProperty *prop;
+
+    QTAILQ_FOREACH(prop, &obj->properties, node) {
+        if (!strstart(prop->type, "child<", NULL)) {
+            continue;
+        }
+
+        if (prop->opaque == child) {
+            object_property_del(obj, prop->name, errp);
+        }
+    }
+}
+
+void object_unparent(Object *obj)
+{
+    if (obj->parent) {
+        object_property_del_child(obj->parent, obj, NULL);
+    }
+}
+
 static void object_deinit(Object *obj, TypeImpl *type)
 {
     if (type->instance_finalize) {
@@ -283,6 +326,8 @@ static void object_deinit(Object *obj, TypeImpl *type)
     if (type_has_parent(type)) {
         object_deinit(obj, type_get_parent(type));
     }
+
+    object_unparent(obj);
 }
 
 void object_finalize(void *data)
@@ -291,6 +336,7 @@ void object_finalize(void *data)
     TypeImpl *ti = obj->class->type;
 
     object_deinit(obj, ti);
+    object_property_del_all(obj);
 }
 
 Object *object_new_with_type(Type type)
@@ -502,3 +548,425 @@ void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
 
     g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
 }
+
+void object_ref(Object *obj)
+{
+    obj->ref++;
+}
+
+void object_unref(Object *obj)
+{
+    g_assert(obj->ref > 0);
+    obj->ref--;
+
+    /* parent always holds a reference to its children */
+    if (obj->ref == 0) {
+        object_finalize(obj);
+    }
+}
+
+void object_property_add(Object *obj, const char *name, const char *type,
+                         ObjectPropertyAccessor *get,
+                         ObjectPropertyAccessor *set,
+                         ObjectPropertyRelease *release,
+                         void *opaque, Error **errp)
+{
+    ObjectProperty *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(&obj->properties, prop, node);
+}
+
+static ObjectProperty *object_property_find(Object *obj, const char *name)
+{
+    ObjectProperty *prop;
+
+    QTAILQ_FOREACH(prop, &obj->properties, node) {
+        if (strcmp(prop->name, name) == 0) {
+            return prop;
+        }
+    }
+
+    return NULL;
+}
+
+void object_property_del(Object *obj, const char *name, Error **errp)
+{
+    ObjectProperty *prop = object_property_find(obj, name);
+
+    QTAILQ_REMOVE(&obj->properties, prop, node);
+
+    prop->release(obj, prop->name, prop->opaque);
+
+    g_free(prop->name);
+    g_free(prop->type);
+    g_free(prop);
+}
+
+void object_property_get(Object *obj, Visitor *v, const char *name,
+                         Error **errp)
+{
+    ObjectProperty *prop = object_property_find(obj, name);
+
+    if (prop == NULL) {
+        error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
+        return;
+    }
+
+    if (!prop->get) {
+        error_set(errp, QERR_PERMISSION_DENIED);
+    } else {
+        prop->get(obj, v, prop->opaque, name, errp);
+    }
+}
+
+void object_property_set(Object *obj, Visitor *v, const char *name,
+                         Error **errp)
+{
+    ObjectProperty *prop = object_property_find(obj, name);
+
+    if (prop == NULL) {
+        error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
+        return;
+    }
+
+    if (!prop->set) {
+        error_set(errp, QERR_PERMISSION_DENIED);
+    } else {
+        prop->set(obj, v, prop->opaque, name, errp);
+    }
+}
+
+const char *object_property_get_type(Object *obj, const char *name, Error **errp)
+{
+    ObjectProperty *prop = object_property_find(obj, name);
+
+    if (prop == NULL) {
+        error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
+        return NULL;
+    }
+
+    return prop->type;
+}
+
+Object *object_get_root(void)
+{
+    static DeviceState *object_root;
+
+    if (!object_root) {
+        object_root = qdev_create(NULL, "container");
+        qdev_init_nofail(object_root);
+    }
+
+    return OBJECT(object_root);
+}
+
+static void object_get_child_property(Object *obj, Visitor *v, void *opaque,
+                                      const char *name, Error **errp)
+{
+    Object *child = opaque;
+    gchar *path;
+
+    path = object_get_canonical_path(child);
+    visit_type_str(v, &path, name, errp);
+    g_free(path);
+}
+
+void object_property_add_child(Object *obj, const char *name,
+                               Object *child, Error **errp)
+{
+    gchar *type;
+
+    type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
+
+    object_property_add(obj, name, type, object_get_child_property,
+                        NULL, NULL, child, errp);
+
+    object_ref(child);
+    g_assert(child->parent == NULL);
+    child->parent = obj;
+
+    g_free(type);
+}
+
+static void object_get_link_property(Object *obj, Visitor *v, void *opaque,
+                                     const char *name, Error **errp)
+{
+    Object **child = opaque;
+    gchar *path;
+
+    if (*child) {
+        path = object_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 object_set_link_property(Object *obj, Visitor *v, void *opaque,
+                                     const char *name, Error **errp)
+{
+    Object **child = opaque;
+    bool ambiguous = false;
+    const char *type;
+    char *path;
+
+    type = object_property_get_type(obj, name, NULL);
+
+    visit_type_str(v, &path, name, errp);
+
+    if (*child) {
+        object_unref(*child);
+    }
+
+    if (strcmp(path, "") != 0) {
+        Object *target;
+
+        target = object_resolve_path(path, &ambiguous);
+        if (target) {
+            gchar *target_type;
+
+            target_type = g_strdup_printf("link<%s>",
+                                          object_get_typename(OBJECT(target)));
+            if (strcmp(target_type, type) == 0) {
+                *child = target;
+                object_ref(target);
+            } else {
+                error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
+            }
+
+            g_free(target_type);
+        } else {
+            error_set(errp, QERR_DEVICE_NOT_FOUND, path);
+        }
+    } else {
+        *child = NULL;
+    }
+
+    g_free(path);
+}
+
+void object_property_add_link(Object *obj, const char *name,
+                              const char *type, Object **child,
+                              Error **errp)
+{
+    gchar *full_type;
+
+    full_type = g_strdup_printf("link<%s>", type);
+
+    object_property_add(obj, name, full_type,
+                        object_get_link_property,
+                        object_set_link_property,
+                        NULL, child, errp);
+
+    g_free(full_type);
+}
+
+gchar *object_get_canonical_path(Object *obj)
+{
+    Object *root = object_get_root();
+    char *newpath = NULL, *path = NULL;
+
+    while (obj != root) {
+        ObjectProperty *prop = NULL;
+
+        g_assert(obj->parent != NULL);
+
+        QTAILQ_FOREACH(prop, &obj->parent->properties, node) {
+            if (!strstart(prop->type, "child<", NULL)) {
+                continue;
+            }
+
+            if (prop->opaque == obj) {
+                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);
+
+        obj = obj->parent;
+    }
+
+    newpath = g_strdup_printf("/%s", path);
+    g_free(path);
+
+    return newpath;
+}
+
+static Object *object_resolve_abs_path(Object *parent,
+                                          gchar **parts,
+                                          int index)
+{
+    ObjectProperty *prop;
+    Object *child;
+
+    if (parts[index] == NULL) {
+        return parent;
+    }
+
+    if (strcmp(parts[index], "") == 0) {
+        return object_resolve_abs_path(parent, parts, index + 1);
+    }
+
+    prop = object_property_find(parent, parts[index]);
+    if (prop == NULL) {
+        return NULL;
+    }
+
+    child = NULL;
+    if (strstart(prop->type, "link<", NULL)) {
+        Object **pchild = prop->opaque;
+        if (*pchild) {
+            child = *pchild;
+        }
+    } else if (strstart(prop->type, "child<", NULL)) {
+        child = prop->opaque;
+    }
+
+    if (!child) {
+        return NULL;
+    }
+
+    return object_resolve_abs_path(child, parts, index + 1);
+}
+
+static Object *object_resolve_partial_path(Object *parent,
+                                              gchar **parts,
+                                              bool *ambiguous)
+{
+    Object *obj;
+    ObjectProperty *prop;
+
+    obj = object_resolve_abs_path(parent, parts, 0);
+
+    QTAILQ_FOREACH(prop, &parent->properties, node) {
+        Object *found;
+
+        if (!strstart(prop->type, "child<", NULL)) {
+            continue;
+        }
+
+        found = object_resolve_partial_path(prop->opaque, parts, ambiguous);
+        if (found) {
+            if (obj) {
+                if (ambiguous) {
+                    *ambiguous = true;
+                }
+                return NULL;
+            }
+            obj = found;
+        }
+
+        if (ambiguous && *ambiguous) {
+            return NULL;
+        }
+    }
+
+    return obj;
+}
+
+Object *object_resolve_path(const char *path, bool *ambiguous)
+{
+    bool partial_path = true;
+    Object *obj;
+    gchar **parts;
+
+    parts = g_strsplit(path, "/", 0);
+    if (parts == NULL || parts[0] == NULL) {
+        g_strfreev(parts);
+        return object_get_root();
+    }
+
+    if (strcmp(parts[0], "") == 0) {
+        partial_path = false;
+    }
+
+    if (partial_path) {
+        if (ambiguous) {
+            *ambiguous = false;
+        }
+        obj = object_resolve_partial_path(object_get_root(), parts, ambiguous);
+    } else {
+        obj = object_resolve_abs_path(object_get_root(), parts, 1);
+    }
+
+    g_strfreev(parts);
+
+    return obj;
+}
+
+typedef struct StringProperty
+{
+    char *(*get)(Object *, Error **);
+    void (*set)(Object *, const char *, Error **);
+} StringProperty;
+
+static void object_property_get_str(Object *obj, Visitor *v, void *opaque,
+                                    const char *name, Error **errp)
+{
+    StringProperty *prop = opaque;
+    char *value;
+
+    value = prop->get(obj, errp);
+    if (value) {
+        visit_type_str(v, &value, name, errp);
+        g_free(value);
+    }
+}
+
+static void object_property_set_str(Object *obj, Visitor *v, void *opaque,
+                                  const char *name, Error **errp)
+{
+    StringProperty *prop = opaque;
+    char *value;
+    Error *local_err = NULL;
+
+    visit_type_str(v, &value, name, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    prop->set(obj, value, errp);
+    g_free(value);
+}
+
+static void object_property_release_str(Object *obj, const char *name,
+                                      void *opaque)
+{
+    StringProperty *prop = opaque;
+    g_free(prop);
+}
+
+void object_property_add_str(Object *obj, const char *name,
+                           char *(*get)(Object *, Error **),
+                           void (*set)(Object *, const char *, Error **),
+                           Error **errp)
+{
+    StringProperty *prop = g_malloc0(sizeof(*prop));
+
+    prop->get = get;
+    prop->set = set;
+
+    object_property_add(obj, name, "string",
+                        get ? object_property_get_str : NULL,
+                        set ? object_property_set_str : NULL,
+                        object_property_release_str,
+                        prop, errp);
+}
commit 0beb4942071e385c16deba03848898865842edc7
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Dec 22 15:29:25 2011 -0600

    qdev: nuke qdev_init_chardev()
    
    I'm sure the intentions were good here, but there's no reason this should be in
    qdev.  Move it to qemu-char where it belongs.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c
index b8acd43..567cb8c 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,
diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c
index 023c644..38dd282 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);
     }
diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c
index fc70490..630ccb7 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);
     }
diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c
index 2999b79..f9a229c 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);
     }
diff --git a/hw/pl011.c b/hw/pl011.c
index 8db2248..752cbf9 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;
diff --git a/hw/qdev.c b/hw/qdev.c
index e82165d..0692a21 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -336,15 +336,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;
diff --git a/hw/qdev.h b/hw/qdev.h
index b33a27c..8f525ec 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -235,8 +235,6 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
 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. ***/
diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c
index 1491bba..1c2b908 100644
--- a/hw/xilinx_uartlite.c
+++ b/hw/xilinx_uartlite.c
@@ -205,7 +205,7 @@ 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;
diff --git a/qemu-char.c b/qemu-char.c
index 27abcb9..b1d80dd 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2903,3 +2903,13 @@ CharDriverState *qemu_chr_find(const char *name)
     }
     return NULL;
 }
+
+/* Get a character (serial) device interface.  */
+CharDriverState *qemu_char_get_next_serial(void)
+{
+    static int next_serial;
+
+    /* FIXME: This function needs to go away: use chardev properties!  */
+    return serial_hds[next_serial++];
+}
+
diff --git a/qemu-char.h b/qemu-char.h
index 8ca1e2d..486644b 100644
--- a/qemu-char.h
+++ b/qemu-char.h
@@ -248,4 +248,6 @@ void qemu_chr_close_mem(CharDriverState *chr);
 QString *qemu_chr_mem_to_qs(CharDriverState *chr);
 size_t qemu_chr_mem_osize(const CharDriverState *chr);
 
+CharDriverState *qemu_char_get_next_serial(void);
+
 #endif
commit ee46d8a5038d06babb6cfb0a177727d85df9b3fc
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Dec 22 15:24:20 2011 -0600

    qdev: split out UI portions into a new function
    
    qdev-monitor.c deals with the -device, device_add, and info qdm/qtree
    interfaces.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/Makefile.objs b/Makefile.objs
index b942625..1a26349 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -113,7 +113,7 @@ common-obj-y += bt-hci-csr.o
 common-obj-y += buffered_file.o migration.o migration-tcp.o
 common-obj-y += qemu-char.o #aio.o
 common-obj-y += msmouse.o ps2.o
-common-obj-y += qdev.o qdev-properties.o
+common-obj-y += qdev.o qdev-properties.o qdev-monitor.o
 common-obj-y += block-migration.o iohandler.o
 common-obj-y += pflib.o
 common-obj-y += bitmap.o bitops.o
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
new file mode 100644
index 0000000..841e1ad
--- /dev/null
+++ b/hw/qdev-monitor.c
@@ -0,0 +1,585 @@
+/*
+ *  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);
+    }
+    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 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);
+    }
+
+    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);
+    }
+
+    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;
+        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;
+}
+
+
+#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.c b/hw/qdev.c
index e2263cb..e82165d 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,10 +37,6 @@ static bool qdev_hot_removed = false;
 static BusState *main_system_bus;
 static void main_system_bus_create(void);
 
-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.  */
 const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
 {
@@ -61,56 +56,12 @@ Property *qdev_get_props(DeviceState *dev)
     return dc->props;
 }
 
-/*
- * 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);
-}
-
 const char *qdev_fw_name(DeviceState *dev)
 {
     DeviceClass *dc = DEVICE_GET_CLASS(dev);
 
     if (dc->fw_name) {
         return dc->fw_name;
-    } else if (qdev_class_has_alias(dc)) {
-        return qdev_class_get_alias(dc);
     }
 
     return object_get_typename(OBJECT(dev));
@@ -181,232 +132,6 @@ DeviceState *qdev_try_create(BusState *bus, const char *name)
     return dev;
 }
 
-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);
-    }
-    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 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);
-    }
-
-    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);
-    }
-
-    return dev;
-}
-
-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(main_system_bus, 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;
-        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.
@@ -723,34 +448,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;
@@ -769,165 +466,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 : 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(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)
 {
@@ -1008,108 +546,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", 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 (main_system_bus)
-        qbus_print(mon, main_system_bus, 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(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;
@@ -1641,12 +1077,6 @@ void qdev_property_add_str(DeviceState *dev, const char *name,
                       prop, errp);
 }
 
-void qdev_machine_init(void)
-{
-    qdev_get_peripheral_anon();
-    qdev_get_peripheral();
-}
-
 static void device_initfn(Object *obj)
 {
     DeviceState *dev = DEVICE(obj);
diff --git a/hw/qdev.h b/hw/qdev.h
index 3d4808d..b33a27c 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -646,4 +646,6 @@ Property *qdev_get_props(DeviceState *dev);
 /* FIXME: make this a link<> */
 void qdev_set_parent_bus(DeviceState *dev, BusState *bus);
 
+extern int qdev_hotplug;
+
 #endif
commit 9fbe61277ff72748850eb746ac33fb9c110d2ae5
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Dec 22 15:14:27 2011 -0600

    qdev: refactor away qdev_create_from_info
    
    Note that the FIXME gets fixed in series 4/4.  We need to convert BusState to
    QOM before we can make parent_bus a link.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev.c b/hw/qdev.c
index 9933ea2..e2263cb 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -124,30 +124,22 @@ bool qdev_exists(const char *name)
 static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
                                      Error **errp);
 
-static DeviceState *qdev_create_from_info(BusState *bus, const char *typename)
+void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
 {
-    DeviceState *dev;
     Property *prop;
 
-    dev = DEVICE(object_new(typename));
-
-    dev->parent_bus = bus;
-    qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
-
     if (qdev_hotplug) {
         assert(bus->allow_hotplug);
     }
 
+    dev->parent_bus = bus;
     QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
 
+    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_prop_set_globals(dev);
-
-    return dev;
 }
 
 /* Create a new device.  This only initializes the device state structure
@@ -172,11 +164,21 @@ DeviceState *qdev_create(BusState *bus, const char *name)
 
 DeviceState *qdev_try_create(BusState *bus, const char *name)
 {
+    DeviceState *dev;
+
+    dev = DEVICE(object_new(name));
+    if (!dev) {
+        return NULL;
+    }
+
     if (!bus) {
         bus = sysbus_get_default();
     }
 
-    return qdev_create_from_info(bus, name);
+    qdev_set_parent_bus(dev, bus);
+    qdev_prop_set_globals(dev);
+
+    return dev;
 }
 
 static void qdev_print_devinfo(ObjectClass *klass, void *opaque)
@@ -373,8 +375,15 @@ DeviceState *qdev_device_add(QemuOpts *opts)
         return NULL;
     }
 
+    if (!bus) {
+        bus = sysbus_get_default();
+    }
+
     /* create device, set properties */
-    qdev = qdev_create_from_info(bus, driver);
+    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;
diff --git a/hw/qdev.h b/hw/qdev.h
index 102c5fa..3d4808d 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -643,4 +643,7 @@ BusInfo *qdev_get_bus_info(DeviceState *dev);
 
 Property *qdev_get_props(DeviceState *dev);
 
+/* FIXME: make this a link<> */
+void qdev_set_parent_bus(DeviceState *dev, BusState *bus);
+
 #endif
commit 9674bfe42070e58242f0048f4f03fde69d570a75
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Dec 22 15:06:37 2011 -0600

    qdev: split out common init to instance_init
    
    This gets us closer to being able to object_new() a qdev type and have a
    functioning object verses having to call qdev_create().
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev.c b/hw/qdev.c
index 5830bef..9933ea2 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -130,31 +130,22 @@ static DeviceState *qdev_create_from_info(BusState *bus, const char *typename)
     Property *prop;
 
     dev = DEVICE(object_new(typename));
+
     dev->parent_bus = bus;
-    qdev_prop_set_defaults(dev, qdev_get_props(dev));
     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 = qdev_get_props(dev); prop && prop->name; prop++) {
-        qdev_property_add_legacy(dev, prop, NULL);
-        qdev_property_add_static(dev, prop, NULL);
-    }
+    QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
 
     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);
+    qdev_prop_set_globals(dev);
 
     return dev;
 }
@@ -1647,6 +1638,29 @@ void qdev_machine_init(void)
     qdev_get_peripheral();
 }
 
+static void device_initfn(Object *obj)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop;
+
+    if (qdev_hotplug) {
+        dev->hotplugged = 1;
+        qdev_hot_added = true;
+    }
+
+    dev->instance_id_alias = -1;
+    QTAILQ_INIT(&dev->properties);
+    dev->state = DEV_STATE_CREATED;
+
+    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);
+    }
+
+    qdev_property_add_str(dev, "type", qdev_get_type, NULL, NULL);
+}
+
 void device_reset(DeviceState *dev)
 {
     DeviceClass *klass = DEVICE_GET_CLASS(dev);
@@ -1660,6 +1674,7 @@ static TypeInfo device_type_info = {
     .name = TYPE_DEVICE,
     .parent = TYPE_OBJECT,
     .instance_size = sizeof(DeviceState),
+    .instance_init = device_initfn,
     .abstract = true,
     .class_size = sizeof(DeviceClass),
 };
commit 5eeee3fa2e646dadeea2c10515956b11ed0de877
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Dec 22 14:40:54 2011 -0600

    qom: add new command to search for types
    
    This adds a command that allows searching for types that implement a property.
    This allows you to do things like search for all available PCIDevices.  In the
    future, we'll also have a standard interface for things with a BlockDriverState
    property that a PCIDevice could implement.
    
    This will enable search queries like, "any type that implements the BlockDevice
    interface" which would allow management tools to present available block devices
    without having to hard code device names.  Since an object can implement
    multiple interfaces, one device could act both as a BlockDevice and a
    NetworkDevice.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/qapi-schema.json b/qapi-schema.json
index 80debe6..56a4123 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1549,3 +1549,36 @@
 # Since: 1.1
 ##
 { 'command': 'block_job_cancel', 'data': { 'device': 'str' } }
+
+##
+# @ObjectTypeInfo:
+#
+# This structure describes a search result from @qom-list-types
+#
+# @name: the type name found in the search
+#
+# Since: 1.1
+#
+# Notes: This command is experimental and may change syntax in future releases.
+##
+{ 'type': 'ObjectTypeInfo',
+  'data': { 'name': 'str' } }
+
+##
+# @qom-list-types:
+#
+# This command will return a list of types given search parameters
+#
+# @implements: if specified, only return types that implement this type name
+#
+# @abstract: if true, include abstract types in the results
+#
+# Returns: a list of @ObjectTypeInfo or an empty list if no results are found
+#
+# Since: 1.1
+#
+# Notes: This command is experimental and may change syntax in future releases.
+##
+{ 'command': 'qom-list-types',
+  'data': { '*implements': 'str', '*abstract': 'bool' },
+  'returns': [ 'ObjectTypeInfo' ] }
diff --git a/qerror.c b/qerror.c
index 637eca7..3d179c8 100644
--- a/qerror.c
+++ b/qerror.c
@@ -161,7 +161,7 @@ static const QErrorStringTable qerror_table[] = {
     },
     {
         .error_fmt = QERR_INVALID_PARAMETER_TYPE,
-        .desc      = "Invalid parameter type, expected: %(expected)",
+        .desc      = "Invalid parameter type for '%(name)', expected: %(expected)",
     },
     {
         .error_fmt = QERR_INVALID_PARAMETER_VALUE,
diff --git a/qmp-commands.hx b/qmp-commands.hx
index bd6b641..b5e2ab8 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2042,3 +2042,8 @@ EQMP
         .args_type  = "password:s",
         .mhandler.cmd_new = qmp_marshal_input_change_vnc_password,
     },
+    {
+        .name       = "qom-list-types",
+        .args_type  = "implements:s?,abstract:b?",
+        .mhandler.cmd_new = qmp_marshal_input_qom_list_types,
+    },
diff --git a/qmp.c b/qmp.c
index 1222b6c..75049ed 100644
--- a/qmp.c
+++ b/qmp.c
@@ -395,3 +395,30 @@ void qmp_change(const char *device, const char *target,
         qmp_change_blockdev(device, target, has_arg, arg, err);
     }
 }
+
+static void qom_list_types_tramp(ObjectClass *klass, void *data)
+{
+    ObjectTypeInfoList *e, **pret = data;
+    ObjectTypeInfo *info;
+
+    info = g_malloc0(sizeof(*info));
+    info->name = g_strdup(object_class_get_name(klass));
+
+    e = g_malloc0(sizeof(*e));
+    e->value = info;
+    e->next = *pret;
+    *pret = e;
+}
+
+ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
+                                       const char *implements,
+                                       bool has_abstract,
+                                       bool abstract,
+                                       Error **errp)
+{
+    ObjectTypeInfoList *ret = NULL;
+
+    object_class_foreach(qom_list_types_tramp, implements, abstract, &ret);
+
+    return ret;
+}
commit 6acbe4c6f18e7de00481ff30574262b58526de45
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Dec 22 11:05:00 2011 -0600

    qdev: remove baked in notion of aliases (v2)
    
    Limit them to the device_add functionality.  Device aliases were a hack based
    on the fact that virtio was modeled the wrong way.  The mechanism for aliasing
    is very limited in that only one alias can exist for any device.
    
    We have to support it for the purposes of compatibility but we only need to
    support it in device_add so restrict it to that piece of code.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    ---
    v1 -> v2
     - Use a table for aliases (Paolo)

diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 0e819f6..5cdaa99 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -158,7 +158,6 @@ static void ich_ahci_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_INTEL_82801IR;
     k->revision = 0x02;
     k->class_id = PCI_CLASS_STORAGE_SATA;
-    dc->alias = "ahci";
     dc->vmsd = &vmstate_ahci;
 }
 
@@ -172,6 +171,5 @@ static TypeInfo ich_ahci_info = {
 static void ich_ahci_register(void)
 {
     type_register_static(&ich_ahci_info);
-    type_register_static_alias(&ich_ahci_info, "ahci");
 }
 device_init(ich_ahci_register);
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 638332e..9a7ffe3 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -2131,7 +2131,6 @@ static void lsi_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_LSI_53C895A;
     k->class_id = PCI_CLASS_STORAGE_SCSI;
     k->subsystem_id = 0x1000;
-    dc->alias = "lsi";
     dc->reset = lsi_scsi_reset;
     dc->vmsd = &vmstate_lsi_scsi;
 }
@@ -2146,7 +2145,6 @@ static TypeInfo lsi_info = {
 static void lsi53c895a_register_devices(void)
 {
     type_register_static(&lsi_info);
-    type_register_static_alias(&lsi_info, "lsi");
 }
 
 device_init(lsi53c895a_register_devices);
diff --git a/hw/qdev.c b/hw/qdev.c
index 4f6c3a7..5830bef 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -61,14 +61,56 @@ Property *qdev_get_props(DeviceState *dev)
     return dc->props;
 }
 
+/*
+ * 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);
+}
+
 const char *qdev_fw_name(DeviceState *dev)
 {
     DeviceClass *dc = DEVICE_GET_CLASS(dev);
 
     if (dc->fw_name) {
         return dc->fw_name;
-    } else if (dc->alias) {
-        return dc->alias;
+    } else if (qdev_class_has_alias(dc)) {
+        return qdev_class_get_alias(dc);
     }
 
     return object_get_typename(OBJECT(dev));
@@ -161,8 +203,8 @@ static void qdev_print_devinfo(ObjectClass *klass, void *opaque)
     if (dc->bus_info) {
         error_printf(", bus %s", dc->bus_info->name);
     }
-    if (dc->alias) {
-        error_printf(", alias \"%s\"", dc->alias);
+    if (qdev_class_has_alias(dc)) {
+        error_printf(", alias \"%s\"", qdev_class_get_alias(dc));
     }
     if (dc->desc) {
         error_printf(", desc \"%s\"", dc->desc);
@@ -188,6 +230,19 @@ static int set_property(const char *name, const char *value, void *opaque)
     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;
@@ -208,6 +263,15 @@ int qdev_device_help(QemuOpts *opts)
 
     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);
@@ -263,6 +327,7 @@ static DeviceState *qdev_get_peripheral_anon(void)
 
 DeviceState *qdev_device_add(QemuOpts *opts)
 {
+    ObjectClass *obj;
     DeviceClass *k;
     const char *driver, *path, *id;
     DeviceState *qdev;
@@ -275,7 +340,22 @@ DeviceState *qdev_device_add(QemuOpts *opts)
     }
 
     /* find driver */
-    k = DEVICE_CLASS(object_class_by_name(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");
@@ -753,7 +833,8 @@ static DeviceState *qbus_find_dev(BusState *bus, char *elem)
     QTAILQ_FOREACH(dev, &bus->children, sibling) {
         DeviceClass *dc = DEVICE_GET_CLASS(dev);
 
-        if (dc->alias && strcmp(dc->alias, elem) == 0) {
+        if (qdev_class_has_alias(dc) &&
+            strcmp(qdev_class_get_alias(dc), elem) == 0) {
             return dev;
         }
     }
diff --git a/hw/qdev.h b/hw/qdev.h
index b56747e..102c5fa 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -78,7 +78,6 @@ typedef struct DeviceClass {
     ObjectClass parent_class;
 
     const char *fw_name;
-    const char *alias;
     const char *desc;
     Property *props;
     int no_user;
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index 4e1e888..b66ef68 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -354,7 +354,6 @@ static void s390_virtio_net_class_init(ObjectClass *klass, void *data)
 
     k->init = s390_virtio_net_init;
     dc->props = s390_virtio_net_properties;
-    dc->alias = "virtio-net";
 }
 
 static TypeInfo s390_virtio_net = {
@@ -377,7 +376,6 @@ static void s390_virtio_blk_class_init(ObjectClass *klass, void *data)
 
     k->init = s390_virtio_blk_init;
     dc->props = s390_virtio_blk_properties;
-    dc->alias = "virtio-blk";
 }
 
 static TypeInfo s390_virtio_blk = {
@@ -400,7 +398,6 @@ static void s390_virtio_serial_class_init(ObjectClass *klass, void *data)
 
     k->init = s390_virtio_serial_init;
     dc->props = s390_virtio_serial_properties;
-    dc->alias = "virtio-serial";
 }
 
 static TypeInfo s390_virtio_serial = {
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index bc96552..93fff54 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -827,7 +827,6 @@ static void virtio_blk_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
     k->revision = VIRTIO_PCI_ABI_VERSION;
     k->class_id = PCI_CLASS_STORAGE_SCSI;
-    dc->alias = "virtio-blk";
     dc->reset = virtio_pci_reset;
     dc->props = virtio_blk_properties;
 }
@@ -862,7 +861,6 @@ static void virtio_net_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
     k->revision = VIRTIO_PCI_ABI_VERSION;
     k->class_id = PCI_CLASS_NETWORK_ETHERNET;
-    dc->alias = "virtio-net";
     dc->reset = virtio_pci_reset;
     dc->props = virtio_net_properties;
 }
@@ -894,7 +892,6 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
     k->revision = VIRTIO_PCI_ABI_VERSION;
     k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
-    dc->alias = "virtio-serial";
     dc->reset = virtio_pci_reset;
     dc->props = virtio_serial_properties;
 }
@@ -922,7 +919,6 @@ static void virtio_balloon_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
     k->revision = VIRTIO_PCI_ABI_VERSION;
     k->class_id = PCI_CLASS_MEMORY_RAM;
-    dc->alias = "virtio-balloon";
     dc->reset = virtio_pci_reset;
     dc->props = virtio_balloon_properties;
 }
@@ -937,13 +933,9 @@ static TypeInfo virtio_balloon_info = {
 static void virtio_pci_register_devices(void)
 {
     type_register_static(&virtio_blk_info);
-    type_register_static_alias(&virtio_blk_info, "virtio-blk");
     type_register_static(&virtio_net_info);
-    type_register_static_alias(&virtio_net_info, "virtio-net");
     type_register_static(&virtio_serial_info);
-    type_register_static_alias(&virtio_serial_info, "virtio-serial");
     type_register_static(&virtio_balloon_info);
-    type_register_static_alias(&virtio_balloon_info, "virtio-balloon");
 }
 
 device_init(virtio_pci_register_devices)
commit d307af795d9fb25680339288a10c9e297e102826
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 9 15:02:56 2011 -0600

    qdev: kill off DeviceInfo
    
    It is no longer used in the tree since everything is done natively through
    QEMU Object Model.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/i2c.c b/hw/i2c.c
index e21a666..8ae4aaa 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -196,7 +196,7 @@ const VMStateDescription vmstate_i2c_slave = {
     }
 };
 
-static int i2c_slave_qdev_init(DeviceState *dev, DeviceInfo *base)
+static int i2c_slave_qdev_init(DeviceState *dev)
 {
     I2CSlave *s = I2C_SLAVE_FROM_QDEV(dev);
     I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s);
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 1335615..1640616 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -53,7 +53,7 @@ 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 = IDE_DEVICE(qdev);
     IDEDeviceClass *dc = IDE_DEVICE_GET_CLASS(dev);
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 9e4a31f..83c42d5 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -47,7 +47,7 @@ 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);
diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index a22c5c6..d03f828 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -110,7 +110,7 @@ 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 = ISA_DEVICE(qdev);
     ISADeviceClass *klass = ISA_DEVICE_GET_CLASS(dev);
diff --git a/hw/pci.c b/hw/pci.c
index 8fd450c..1df05ae 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1453,7 +1453,7 @@ 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;
     PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
diff --git a/hw/qdev.c b/hw/qdev.c
index a30a1c2..4f6c3a7 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -43,49 +43,6 @@ static BusState *qbus_find_recursive(BusState *bus, const char *name,
 static BusState *qbus_find(const char *path);
 
 /* Register a new device type.  */
-static void qdev_subclass_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    DeviceInfo *info = data;
-
-    if (info->fw_name) {
-        dc->fw_name = info->fw_name;
-    }
-    if (info->alias) {
-        dc->alias = info->alias;
-    }
-    if (info->desc) {
-        dc->desc = info->desc;
-    }
-    if (info->props) {
-        dc->props = info->props;
-    }
-    if (info->no_user) {
-        dc->no_user = info->no_user;
-    }
-    if (info->reset) {
-        dc->reset = info->reset;
-    }
-    if (info->vmsd) {
-        dc->vmsd = info->vmsd;
-    }
-    if (info->init) {
-        dc->init = info->init;
-    }
-    if (info->unplug) {
-        dc->unplug = info->unplug;
-    }
-    if (info->exit) {
-        dc->exit = info->exit;
-    }
-    if (info->bus_info) {
-        dc->bus_info = info->bus_info;
-    }
-    if (info->class_init) {
-        info->class_init(klass, data);
-    }
-}
-
 const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
 {
     DeviceClass *dc = DEVICE_GET_CLASS(dev);
@@ -117,30 +74,6 @@ const char *qdev_fw_name(DeviceState *dev)
     return object_get_typename(OBJECT(dev));
 }
 
-static void qdev_do_register_subclass(DeviceInfo *info, const char *parent,
-                                      const char *name)
-{
-    TypeInfo type_info = {};
-
-    assert(info->size >= sizeof(DeviceState));
-
-    type_info.name = name;
-    type_info.parent = parent;
-    type_info.instance_size = info->size;
-    type_info.class_init = qdev_subclass_init;
-    type_info.class_data = info;
-
-    type_register_static(&type_info);
-}
-
-void qdev_register_subclass(DeviceInfo *info, const char *parent)
-{
-    qdev_do_register_subclass(info, parent, info->name);
-    if (info->alias) {
-        qdev_do_register_subclass(info, parent, info->alias);
-    }
-}
-
 bool qdev_exists(const char *name)
 {
     return !!object_class_by_name(name);
@@ -406,8 +339,7 @@ int qdev_init(DeviceState *dev)
 
     assert(dev->state == DEV_STATE_CREATED);
 
-    /* FIXME hopefully this doesn't break anything */
-    rc = dc->init(dev, NULL);
+    rc = dc->init(dev);
     if (rc < 0) {
         qdev_free(dev);
         return rc;
diff --git a/hw/qdev.h b/hw/qdev.h
index ce76625..b56747e 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -14,8 +14,6 @@ typedef struct PropertyInfo PropertyInfo;
 
 typedef struct CompatProperty CompatProperty;
 
-typedef struct DeviceInfo DeviceInfo;
-
 typedef struct BusState BusState;
 
 typedef struct BusInfo BusInfo;
@@ -72,7 +70,7 @@ typedef struct DeviceProperty
 #define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE)
 #define DEVICE_GET_CLASS(obj) OBJECT_GET_CLASS(DeviceClass, (obj), TYPE_DEVICE)
 
-typedef int (*qdev_initfn)(DeviceState *dev, DeviceInfo *info);
+typedef int (*qdev_initfn)(DeviceState *dev);
 typedef int (*qdev_event)(DeviceState *dev);
 typedef void (*qdev_resetfn)(DeviceState *dev);
 
@@ -233,35 +231,6 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
 
 /*** Device API.  ***/
 
-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;
-
-    /**
-     * See #TypeInfo::class_init()
-     */
-    void (*class_init)(ObjectClass *klass, void *data);
-
-    /* Private to qdev / bus.  */
-    qdev_initfn init;
-    qdev_event unplug;
-    qdev_event exit;
-    BusInfo *bus_info;
-};
-
-void qdev_register_subclass(DeviceInfo *info, const char *parent);
-
 /* Register device properties.  */
 /* GPIO inputs also double as IRQ sinks.  */
 void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index a0c610a..4e1e888 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -410,7 +410,7 @@ static TypeInfo s390_virtio_serial = {
     .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)
 {
     VirtIOS390Device *_dev = (VirtIOS390Device *)dev;
     VirtIOS390DeviceClass *_info = VIRTIO_S390_DEVICE_GET_CLASS(dev);
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index b75044f..0ee50a8 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -115,7 +115,7 @@ 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 = SCSI_DEVICE(qdev);
     SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index d39a47b..64f0009 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -649,7 +649,7 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev)
     return 0;
 }
 
-static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
+static int spapr_vio_busdev_init(DeviceState *qdev)
 {
     VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
     VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
diff --git a/hw/ssi.c b/hw/ssi.c
index 4282b8b..ead446c 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -21,7 +21,7 @@ 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)
 {
     SSISlave *s = SSI_SLAVE(dev);
     SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
diff --git a/hw/sysbus.c b/hw/sysbus.c
index 4870dbf..282060a 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -105,7 +105,7 @@ 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)
 {
     SysBusDevice *sd = SYS_BUS_DEVICE(dev);
     SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(sd);
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index d07f844..b753834 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -156,7 +156,7 @@ void usb_device_set_interface(USBDevice *dev, int interface,
     }
 }
 
-static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int usb_qdev_init(DeviceState *qdev)
 {
     USBDevice *dev = USB_DEVICE(qdev);
     int rc;
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index 844f873..881da30 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -1161,7 +1161,7 @@ static int ccid_card_exit(DeviceState *qdev)
     return ret;
 }
 
-static int ccid_card_init(DeviceState *qdev, DeviceInfo *base)
+static int ccid_card_init(DeviceState *qdev)
 {
     CCIDCardState *card = CCID_CARD(qdev);
     USBCCIDState *s =
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 50a6d7f..6117629 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -748,7 +748,7 @@ 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);
     VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
commit 39bffca2030950ef6efe57c2fac8327a45ae1015
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Dec 7 21:34:16 2011 -0600

    qdev: register all types natively through QEMU Object Model
    
    This was done in a mostly automated fashion.  I did it in three steps and then
    rebased it into a single step which avoids repeatedly touching every file in
    the tree.
    
    The first step was a sed-based addition of the parent type to the subclass
    registration functions.
    
    The second step was another sed-based removal of subclass registration functions
    while also adding virtual functions from the base class into a class_init
    function as appropriate.
    
    Finally, a python script was used to convert the DeviceInfo structures and
    qdev_register_subclass functions to TypeInfo structures, class_init functions,
    and type_register_static calls.
    
    We are almost fully converted to QOM after this commit.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index aded048..3f15540 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -174,6 +174,7 @@ static Property virtio_9p_properties[] = {
 
 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;
@@ -181,19 +182,20 @@ static void virtio_9p_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo virtio_9p_info = {
-    .name = "virtio-9p-pci",
-    .size = sizeof(VirtIOPCIProxy),
-    .props = virtio_9p_properties,
-    .class_init = virtio_9p_class_init,
-    .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 b42c475..19de12b 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -208,35 +208,39 @@ static const VMStateDescription vmstate_a9mp_priv = {
     }
 };
 
+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 DeviceInfo a9mp_priv_info = {
-    .name = "a9mpcore_priv",
-    .size  = sizeof(a9mp_priv_state),
-    .vmsd = &vmstate_a9mp_priv,
-    .reset = a9mp_priv_reset,
-    .class_init = a9mp_priv_class_init,
-    .props = (Property[]) {
-        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 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 33b85f5..ed2e4cd 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -1351,6 +1351,7 @@ static Property ac97_properties[] = {
 
 static void ac97_class_init(ObjectClass *klass, void *data)
 {
+    DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
     k->init = ac97_initfn;
@@ -1359,20 +1360,21 @@ static void ac97_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo ac97_info = {
-    .name = "AC97",
-    .desc = "Intel 82801AA AC97 Audio",
-    .size = sizeof (AC97LinkState),
-    .vmsd = &vmstate_ac97,
-    .props = ac97_properties,
-    .class_init = ac97_class_init,
+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 9058a7c..21484ae 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -403,6 +403,7 @@ static Property piix4_pm_properties[] = {
 
 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;
@@ -412,21 +413,22 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo piix4_pm_info = {
-    .name = "PIIX4_PM",
-    .desc = "PM",
-    .size = sizeof(PIIX4PMState),
-    .vmsd = &vmstate_acpi,
-    .no_user = 1,
-    .props = piix4_pm_properties,
-    .class_init = piix4_pm_class_init,
+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);
diff --git a/hw/ads7846.c b/hw/ads7846.c
index c1b894e..3cfdecb 100644
--- a/hw/ads7846.c
+++ b/hw/ads7846.c
@@ -161,15 +161,16 @@ static void ads7846_class_init(ObjectClass *klass, void *data)
     k->transfer = ads7846_transfer;
 }
 
-static DeviceInfo ads7846_info = {
-    .name = "ads7846",
-    .size = sizeof(ADS7846State),
-    .class_init = ads7846_class_init,
+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_typhoon.c b/hw/alpha_typhoon.c
index 8a68c7c..736c28a 100644
--- a/hw/alpha_typhoon.c
+++ b/hw/alpha_typhoon.c
@@ -810,20 +810,22 @@ static int typhoon_pcihost_init(SysBusDevice *dev)
 
 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 DeviceInfo typhoon_pcihost_info = {
-    .name = "typhoon-pcihost",
-    .size = sizeof(TyphoonState),
-    .no_user = 1,
-    .class_init = typhoon_pcihost_class_init,
+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 1a45420..c7aaa72 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -447,28 +447,32 @@ static void pbm_pci_host_class_init(ObjectClass *klass, void *data)
     k->is_bridge = 1;
 }
 
-static DeviceInfo pbm_pci_host_info = {
-    .name = "pbm-pci",
-    .size = sizeof(PCIDevice),
-    .class_init = pbm_pci_host_class_init,
+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 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 DeviceInfo pbm_host_info = {
-    .name = "pbm",
-    .size = sizeof(APBState),
-    .reset = pci_pbm_reset,
-    .class_init = pbm_host_class_init,
+static TypeInfo pbm_host_info = {
+    .name          = "pbm",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(APBState),
+    .class_init    = pbm_host_class_init,
 };
 
 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;
@@ -478,21 +482,22 @@ static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo pbm_pci_bridge_info = {
-    .name = "pbm-bridge",
-    .size = sizeof(PCIBridge),
-    .vmsd = &vmstate_pci_device,
-    .reset = pci_bridge_reset,
-    .class_init = pbm_pci_bridge_class_init,
+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 353119d..086c544 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -774,14 +774,16 @@ static void apic_class_init(ObjectClass *klass, void *data)
     k->post_load = apic_post_load;
 }
 
-static DeviceInfo apic_info = {
-    .name = "apic",
-    .class_init = apic_class_init,
+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)
 {
-    apic_qdev_register(&apic_info);
+    type_register_static(&apic_info);
 }
 
 device_init(apic_register_devices)
diff --git a/hw/apic_common.c b/hw/apic_common.c
index 9a3b1c5..26991b4 100644
--- a/hw/apic_common.c
+++ b/hw/apic_common.c
@@ -295,7 +295,12 @@ static Property apic_properties_common[] = {
 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;
 }
 
@@ -308,16 +313,6 @@ static TypeInfo apic_common_type = {
     .abstract = true,
 };
 
-void apic_qdev_register(DeviceInfo *info)
-{
-    info->size = sizeof(APICCommonState),
-    info->vmsd = &vmstate_apic_common;
-    info->reset = apic_reset_common;
-    info->no_user = 1;
-    info->props = apic_properties_common;
-    sysbus_qdev_register_subclass(info, TYPE_APIC_COMMON);
-}
-
 static void register_devices(void)
 {
     type_register_static(&apic_common_type);
diff --git a/hw/apic_internal.h b/hw/apic_internal.h
index 1c6971c..0cab010 100644
--- a/hw/apic_internal.h
+++ b/hw/apic_internal.h
@@ -117,7 +117,6 @@ struct APICCommonState {
 };
 
 void apic_report_irq_delivered(int delivered);
-void apic_qdev_register(DeviceInfo *info);
 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 a6e88bc..b06487f 100644
--- a/hw/applesmc.c
+++ b/hw/applesmc.c
@@ -220,28 +220,32 @@ static int applesmc_isa_init(ISADevice *dev)
     return 0;
 }
 
+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 DeviceInfo applesmc_isa_info = {
-    .name  = "isa-applesmc",
-    .size  = sizeof(struct AppleSMCStatus),
-    .reset = qdev_applesmc_isa_reset,
-    .class_init = qdev_applesmc_class_init,
-    .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 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/arm11mpcore.c b/hw/arm11mpcore.c
index 53c5408..3c0839c 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -217,16 +217,18 @@ static Property mpcore_rirq_properties[] = {
 
 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 DeviceInfo mpcore_rirq_info = {
-    .name = "realview_mpcore",
-    .size = sizeof(mpcore_rirq_state),
-    .props = mpcore_rirq_properties,
-    .class_init = mpcore_rirq_class_init,
+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[] = {
@@ -236,22 +238,24 @@ static Property mpcore_priv_properties[] = {
 
 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 DeviceInfo mpcore_priv_info = {
-    .name = "arm11mpcore_priv",
-    .size = sizeof(mpcore_priv_state),
-    .props = mpcore_priv_properties,
-    .class_init = mpcore_priv_class_init,
+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_l2x0.c b/hw/arm_l2x0.c
index 7c5fe32..ba26abc 100644
--- a/hw/arm_l2x0.c
+++ b/hw/arm_l2x0.c
@@ -160,29 +160,33 @@ static int l2x0_priv_init(SysBusDevice *dev)
     return 0;
 }
 
+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 DeviceInfo l2x0_info = {
+static TypeInfo l2x0_info = {
     .name = "l2x0",
-    .size = sizeof(l2x0_state),
-    .vmsd = &vmstate_l2x0,
-    .no_user = 1,
-    .props = (Property[]) {
-        DEFINE_PROP_UINT32("type", l2x0_state, cache_type, 0x1c100100),
-        DEFINE_PROP_END_OF_LIST(),
-    },
-    .reset = l2x0_priv_reset,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(l2x0_state),
     .class_init = l2x0_class_init,
 };
 
 static void l2x0_register_device(void)
 {
-    sysbus_qdev_register(&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 06319c2..5a02365 100644
--- a/hw/arm_mptimer.c
+++ b/hw/arm_mptimer.c
@@ -311,29 +311,33 @@ static const VMStateDescription vmstate_arm_mptimer = {
     }
 };
 
+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 DeviceInfo arm_mptimer_info = {
-    .name = "arm_mptimer",
-    .size = sizeof(arm_mptimer_state),
-    .vmsd = &vmstate_arm_mptimer,
-    .reset = arm_mptimer_reset,
-    .no_user = 1,
-    .class_init = arm_mptimer_class_init,
-    .props = (Property[]) {
-        DEFINE_PROP_UINT32("num-cpu", arm_mptimer_state, num_cpu, 0),
-        DEFINE_PROP_END_OF_LIST()
-    }
+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 08fb443..9d25799 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -409,23 +409,25 @@ static Property arm_sysctl_properties[] = {
 
 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 DeviceInfo arm_sysctl_info = {
-    .name = "realview_sysctl",
-    .size = sizeof(arm_sysctl_state),
-    .vmsd = &vmstate_arm_sysctl,
-    .reset = arm_sysctl_reset,
-    .props = arm_sysctl_properties,
-    .class_init = arm_sysctl_class_init,
+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 15eb37c..1019d41 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -354,34 +354,39 @@ static void icp_pit_class_init(ObjectClass *klass, void *data)
     sdc->init = icp_pit_init;
 }
 
-static DeviceInfo icp_pit_info = {
-    .name = "integrator_pit",
-    .size = sizeof(icp_pit_state),
-    .class_init = icp_pit_class_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 DeviceInfo sp804_info = {
-    .name = "sp804",
-    .size = sizeof(sp804_state),
-    .class_init = sp804_class_init,
-    .props = (Property[]) {
-        DEFINE_PROP_UINT32("freq0", sp804_state, freq0, 1000000),
-        DEFINE_PROP_UINT32("freq1", sp804_state, freq1, 1000000),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+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_qdev_register(&icp_pit_info);
-    sysbus_qdev_register(&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 884fc90..de3d7e0 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -252,21 +252,23 @@ static Property bitband_properties[] = {
 
 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 DeviceInfo bitband_info = {
-    .name = "ARM,bitband-memory",
-    .size = sizeof(BitBandState),
-    .props = bitband_properties,
-    .class_init = bitband_class_init,
+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 2bb94e8..1ed0abc 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -391,31 +391,35 @@ static int armv7m_nvic_init(SysBusDevice *dev)
     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 DeviceInfo armv7m_nvic_priv_info = {
-    .name = "armv7m_nvic",
-    .size = sizeof(nvic_state),
-    .vmsd  = &vmstate_nvic,
-    .class_init = armv7m_nvic_class_init,
-    .props = (Property[]) {
-        /* 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 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_qdev_register(&armv7m_nvic_priv_info);
+    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 da9e5cf..c9c1182 100644
--- a/hw/bitbang_i2c.c
+++ b/hw/bitbang_i2c.c
@@ -223,21 +223,23 @@ static int gpio_i2c_init(SysBusDevice *dev)
 
 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 DeviceInfo gpio_i2c_info = {
-    .name = "gpio_i2c",
-    .desc = "Virtual GPIO to I2C bridge",
-    .size = sizeof(GPIOI2CState),
-    .class_init = gpio_i2c_class_init,
+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/bonito.c b/hw/bonito.c
index 0333a2e..7350a4f 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -768,6 +768,7 @@ PCIBus *bonito_init(qemu_irq *pic)
 
 static void bonito_class_init(ObjectClass *klass, void *data)
 {
+    DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
     k->init = bonito_initfn;
@@ -775,34 +776,37 @@ static void bonito_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo bonito_info = {
-    .name = "Bonito",
-    .desc = "Host bridge",
-    .size = sizeof(PCIBonitoState),
-    .vmsd = &vmstate_bonito,
-    .no_user = 1,
-    .class_init = bonito_class_init,
+static TypeInfo bonito_info = {
+    .name          = "Bonito",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIBonitoState),
+    .class_init    = bonito_class_init,
 };
 
 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 DeviceInfo bonito_pcihost_info = {
-    .name = "Bonito-pcihost",
-    .size = sizeof(BonitoState),
-    .no_user = 1,
-    .class_init = bonito_pcihost_class_init,
+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 6dabe7a..9510ed4 100644
--- a/hw/ccid-card-emulated.c
+++ b/hw/ccid-card-emulated.c
@@ -564,36 +564,39 @@ static int emulated_exitfn(CCIDCardState *base)
     return 0;
 }
 
+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 DeviceInfo emulated_card_info = {
-    .name = EMULATED_DEV_NAME,
-    .desc = "emulated smartcard",
-    .size = sizeof(EmulatedState),
-    .unplug    = qdev_simple_unplug_cb,
-    .class_init = emulated_class_initfn,
-    .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 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 f563d97..a7006ca 100644
--- a/hw/ccid-card-passthru.c
+++ b/hw/ccid-card-passthru.c
@@ -316,32 +316,36 @@ static VMStateDescription passthru_vmstate = {
     }
 };
 
+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 DeviceInfo passthru_card_info = {
-    .name = PASSTHRU_DEV_NAME,
-    .desc = "passthrough smartcard",
-    .size = sizeof(PassthruState),
-    .vmsd = &passthru_vmstate,
-    .class_init = passthru_class_initfn,
-    .props     = (Property[]) {
-        DEFINE_PROP_CHR("chardev", PassthruState, cs),
-        DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+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 9e4979c..6adc745 100644
--- a/hw/ccid.h
+++ b/hw/ccid.h
@@ -54,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(DeviceInfo *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 c203080..116e2b1 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2901,20 +2901,22 @@ static int vga_initfn(ISADevice *dev)
 static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data)
 {
     ISADeviceClass *k = ISA_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
 
-    k->init          = vga_initfn;
+    dc->vmsd  = &vmstate_cirrus_vga;
+    k->init   = vga_initfn;
 }
 
-static DeviceInfo isa_cirrus_vga_info = {
-    .name     = "isa-cirrus-vga",
-    .size     = sizeof(ISACirrusVGAState),
-    .vmsd     = &vmstate_cirrus_vga,
+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)
 {
-    isa_qdev_register(&isa_cirrus_vga_info);
+    type_register_static(&isa_cirrus_vga_info);
 }
 device_init(isa_cirrus_vga_register)
 
@@ -2965,6 +2967,7 @@ DeviceState *pci_cirrus_vga_init(PCIBus *bus)
 
 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;
@@ -2973,18 +2976,19 @@ static void cirrus_vga_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo cirrus_vga_info = {
-    .name = "cirrus-vga",
-    .desc = "Cirrus CLGD 54xx VGA",
-    .size = sizeof(PCICirrusVGAState),
-    .vmsd = &vmstate_pci_cirrus_vga,
-    .class_init = cirrus_vga_class_init,
+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/container.c b/hw/container.c
index 73f94c5..1e97031 100644
--- a/hw/container.c
+++ b/hw/container.c
@@ -7,21 +7,23 @@ static int container_initfn(SysBusDevice *dev)
 
 static void container_class_init(ObjectClass *klass, void *data)
 {
+    DeviceClass *dc = DEVICE_CLASS(klass);
     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
     k->init = container_initfn;
+    dc->no_user = 1;
 }
 
-static DeviceInfo container_info = {
-    .name = "container",
-    .size = sizeof(SysBusDevice),
-    .no_user = 1,
-    .class_init = container_class_init,
+static TypeInfo container_info = {
+    .name          = "container",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SysBusDevice),
+    .class_init    = container_class_init,
 };
 
 static void container_init(void)
 {
-    sysbus_register_withprop(&container_info);
+    type_register_static(&container_info);
 }
 
 device_init(container_init);
diff --git a/hw/cs4231.c b/hw/cs4231.c
index 87c4eb9..c0badbf 100644
--- a/hw/cs4231.c
+++ b/hw/cs4231.c
@@ -157,23 +157,25 @@ static Property cs4231_properties[] = {
 
 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 DeviceInfo cs4231_info = {
-    .name = "SUNW,CS4231",
-    .size = sizeof(CSState),
-    .vmsd = &vmstate_cs4231,
-    .reset = cs_reset,
-    .props = cs4231_properties,
-    .class_init = cs4231_class_init,
+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 811c76b..811dda6 100644
--- a/hw/cs4231a.c
+++ b/hw/cs4231a.c
@@ -665,28 +665,32 @@ int cs4231a_init (ISABus *bus)
     return 0;
 }
 
+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 DeviceInfo cs4231a_info = {
-    .name     = "cs4231a",
-    .desc     = "Crystal Semiconductor CS4231A",
-    .size     = sizeof (CSState),
-    .vmsd     = &vmstate_cs4231a,
-    .class_init = cs4231a_class_initfn,
-    .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 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 f290122..3903b26 100644
--- a/hw/debugcon.c
+++ b/hw/debugcon.c
@@ -87,27 +87,31 @@ static int debugcon_isa_initfn(ISADevice *dev)
     return 0;
 }
 
+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 DeviceInfo debugcon_isa_info = {
-    .name  = "isa-debugcon",
-    .size  = sizeof(ISADebugconState),
-    .class_init = debugcon_isa_class_initfn,
-    .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 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 333bad9..a40fbcf 100644
--- a/hw/dec_pci.c
+++ b/hw/dec_pci.c
@@ -52,6 +52,7 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
 
 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;
@@ -60,15 +61,16 @@ static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo dec_21154_pci_bridge_info = {
-    .name = "dec-21154-p2p-bridge",
-    .desc = "DEC 21154 PCI-PCI bridge",
-    .size = sizeof(PCIBridge),
-    .vmsd = &vmstate_pci_device,
-    .reset = pci_bridge_reset,
-    .class_init = dec_21154_pci_bridge_class_init,
+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)
@@ -117,10 +119,11 @@ static void dec_21154_pci_host_class_init(ObjectClass *klass, void *data)
     k->is_bridge = 1;
 }
 
-static DeviceInfo dec_21154_pci_host_info = {
-    .name = "dec-21154",
-    .size = sizeof(PCIDevice),
-    .class_init = dec_21154_pci_host_class_init,
+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)
@@ -130,17 +133,18 @@ static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data)
     sdc->init = pci_dec_21154_device_init;
 }
 
-static DeviceInfo pci_dec_21154_device_info = {
-    .name = "dec-21154-sysbus",
-    .size = sizeof(DECState),
-    .class_init = pci_dec_21154_device_class_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_qdev_register(&pci_dec_21154_device_info);
-    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 5890b16..539bceb 100644
--- a/hw/ds1225y.c
+++ b/hw/ds1225y.c
@@ -142,22 +142,24 @@ static Property nvram_sysbus_properties[] = {
 
 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 DeviceInfo nvram_sysbus_info = {
-    .name = "ds1225y",
-    .size = sizeof(SysBusNvRamState),
-    .vmsd = &vmstate_nvram,
-    .props = nvram_sysbus_properties,
-    .class_init = nvram_sysbus_class_init,
+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 4e09efe..b137e13 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -128,15 +128,16 @@ static void ds1338_class_init(ObjectClass *klass, void *data)
     k->send = ds1338_send;
 }
 
-static DeviceInfo ds1338_info = {
-    .name = "ds1338",
-    .size = sizeof(DS1338State),
-    .class_init = ds1338_class_init,
+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 200eed6..751f79d 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -1204,6 +1204,7 @@ static Property e1000_properties[] = {
 
 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;
@@ -1213,21 +1214,22 @@ static void e1000_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo e1000_info = {
-    .name = "e1000",
-    .desc = "Intel Gigabit Ethernet",
-    .size = sizeof(E1000State),
-    .reset = qdev_e1000_reset,
-    .vmsd = &vmstate_e1000,
-    .props = e1000_properties,
-    .class_init = e1000_class_init,
+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 2d82c48..1cf2090 100644
--- a/hw/eccmemctl.c
+++ b/hw/eccmemctl.c
@@ -315,24 +315,26 @@ static Property ecc_properties[] = {
 
 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 DeviceInfo ecc_info = {
-    .name = "eccmemctl",
-    .size = sizeof(ECCState),
-    .vmsd = &vmstate_ecc,
-    .reset = ecc_reset,
-    .props = ecc_properties,
-    .class_init = ecc_class_init,
+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 9f6d333..843610c 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -128,8 +128,8 @@
 #define DRVR_INT        0x0200  /* Driver generated interrupt. */
 
 typedef struct {
-    DeviceInfo qdev;
-
+    const char *name;
+    const char *desc;
     uint16_t device_id;
     uint8_t revision;
     uint16_t subsystem_vendor_id;
@@ -1905,8 +1905,8 @@ static int e100_nic_init(PCIDevice *pci_dev)
 
 static E100PCIDeviceInfo e100_devices[] = {
     {
-        .qdev.name = "i82550",
-        .qdev.desc = "Intel i82550 Ethernet",
+        .name = "i82550",
+        .desc = "Intel i82550 Ethernet",
         .device = i82550,
         /* TODO: check device id. */
         .device_id = PCI_DEVICE_ID_INTEL_82551IT,
@@ -1918,8 +1918,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
-        .qdev.name = "i82551",
-        .qdev.desc = "Intel i82551 Ethernet",
+        .name = "i82551",
+        .desc = "Intel i82551 Ethernet",
         .device = i82551,
         .device_id = PCI_DEVICE_ID_INTEL_82551IT,
         /* Revision ID: 0x0f, 0x10. */
@@ -1929,29 +1929,29 @@ static E100PCIDeviceInfo e100_devices[] = {
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
-        .qdev.name = "i82557a",
-        .qdev.desc = "Intel i82557A Ethernet",
+        .name = "i82557a",
+        .desc = "Intel i82557A Ethernet",
         .device = i82557A,
         .device_id = PCI_DEVICE_ID_INTEL_82557,
         .revision = 0x01,
         .power_management = false,
     },{
-        .qdev.name = "i82557b",
-        .qdev.desc = "Intel i82557B Ethernet",
+        .name = "i82557b",
+        .desc = "Intel i82557B Ethernet",
         .device = i82557B,
         .device_id = PCI_DEVICE_ID_INTEL_82557,
         .revision = 0x02,
         .power_management = false,
     },{
-        .qdev.name = "i82557c",
-        .qdev.desc = "Intel i82557C Ethernet",
+        .name = "i82557c",
+        .desc = "Intel i82557C Ethernet",
         .device = i82557C,
         .device_id = PCI_DEVICE_ID_INTEL_82557,
         .revision = 0x03,
         .power_management = false,
     },{
-        .qdev.name = "i82558a",
-        .qdev.desc = "Intel i82558A Ethernet",
+        .name = "i82558a",
+        .desc = "Intel i82558A Ethernet",
         .device = i82558A,
         .device_id = PCI_DEVICE_ID_INTEL_82557,
         .revision = 0x04,
@@ -1959,8 +1959,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
-        .qdev.name = "i82558b",
-        .qdev.desc = "Intel i82558B Ethernet",
+        .name = "i82558b",
+        .desc = "Intel i82558B Ethernet",
         .device = i82558B,
         .device_id = PCI_DEVICE_ID_INTEL_82557,
         .revision = 0x05,
@@ -1968,8 +1968,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
-        .qdev.name = "i82559a",
-        .qdev.desc = "Intel i82559A Ethernet",
+        .name = "i82559a",
+        .desc = "Intel i82559A Ethernet",
         .device = i82559A,
         .device_id = PCI_DEVICE_ID_INTEL_82557,
         .revision = 0x06,
@@ -1977,8 +1977,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
-        .qdev.name = "i82559b",
-        .qdev.desc = "Intel i82559B Ethernet",
+        .name = "i82559b",
+        .desc = "Intel i82559B Ethernet",
         .device = i82559B,
         .device_id = PCI_DEVICE_ID_INTEL_82557,
         .revision = 0x07,
@@ -1986,8 +1986,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
-        .qdev.name = "i82559c",
-        .qdev.desc = "Intel i82559C Ethernet",
+        .name = "i82559c",
+        .desc = "Intel i82559C Ethernet",
         .device = i82559C,
         .device_id = PCI_DEVICE_ID_INTEL_82557,
 #if 0
@@ -2003,8 +2003,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
-        .qdev.name = "i82559er",
-        .qdev.desc = "Intel i82559ER Ethernet",
+        .name = "i82559er",
+        .desc = "Intel i82559ER Ethernet",
         .device = i82559ER,
         .device_id = PCI_DEVICE_ID_INTEL_82551IT,
         .revision = 0x09,
@@ -2012,8 +2012,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .has_extended_tcb_support = true,
         .power_management = true,
     },{
-        .qdev.name = "i82562",
-        .qdev.desc = "Intel i82562 Ethernet",
+        .name = "i82562",
+        .desc = "Intel i82562 Ethernet",
         .device = i82562,
         /* TODO: check device id. */
         .device_id = PCI_DEVICE_ID_INTEL_82551IT,
@@ -2024,8 +2024,8 @@ static E100PCIDeviceInfo e100_devices[] = {
         .power_management = true,
     },{
         /* Toshiba Tecra 8200. */
-        .qdev.name = "i82801",
-        .qdev.desc = "Intel i82801 Ethernet",
+        .name = "i82801",
+        .desc = "Intel i82801 Ethernet",
         .device = i82801,
         .device_id = 0x2449,
         .revision = 0x03,
@@ -2048,7 +2048,7 @@ static E100PCIDeviceInfo *eepro100_get_class_by_name(const char *typename)
      * do this in a much more elegant fashion.
      */
     for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
-        if (strcmp(e100_devices[i].qdev.name, typename) == 0) {
+        if (strcmp(e100_devices[i].name, typename) == 0) {
             info = &e100_devices[i];
             break;
         }
@@ -2063,13 +2063,21 @@ 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";
@@ -2081,22 +2089,19 @@ static void eepro100_class_init(ObjectClass *klass, void *data)
     k->subsystem_id = info->subsystem_id;
 }
 
-static Property e100_properties[] = {
-    DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
 static void eepro100_register_devices(void)
 {
     size_t i;
     for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
-        DeviceInfo *info = &e100_devices[i].qdev;
+        TypeInfo type_info = {};
+        E100PCIDeviceInfo *info = &e100_devices[i];
 
-        info->class_init = eepro100_class_init;
-        info->size = sizeof(EEPRO100State);
-        info->props = e100_properties;
+        type_info.name = info->name;
+        type_info.parent = TYPE_PCI_DEVICE;
+        type_info.class_init = eepro100_class_init;
+        type_info.instance_size = sizeof(EEPRO100State);
         
-        pci_qdev_register(info);
+        type_register(&type_info);
     }
 }
 
diff --git a/hw/empty_slot.c b/hw/empty_slot.c
index 70e45d0..1bc1815 100644
--- a/hw/empty_slot.c
+++ b/hw/empty_slot.c
@@ -83,15 +83,16 @@ static void empty_slot_class_init(ObjectClass *klass, void *data)
     k->init = empty_slot_init1;
 }
 
-static DeviceInfo empty_slot_info = {
-    .name = "empty_slot",
-    .size = sizeof(EmptySlot),
-    .class_init = empty_slot_class_init,
+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 205bed7..95e88b9 100644
--- a/hw/es1370.c
+++ b/hw/es1370.c
@@ -1033,6 +1033,7 @@ int es1370_init (PCIBus *bus)
 
 static void es1370_class_init(ObjectClass *klass, void *data)
 {
+    DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
     k->init = es1370_initfn;
@@ -1042,19 +1043,20 @@ static void es1370_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo es1370_info = {
-    .name = "ES1370",
-    .desc = "ENSONIQ AudioPCI ES1370",
-    .size = sizeof (ES1370State),
-    .vmsd = &vmstate_es1370,
-    .class_init = es1370_class_init,
+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 d905d96..9fe282f 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -915,23 +915,25 @@ static Property escc_properties[] = {
 
 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 DeviceInfo escc_info = {
-    .name = "escc",
-    .size = sizeof(SerialState),
-    .vmsd = &vmstate_escc,
-    .reset = escc_reset,
-    .props = escc_properties,
-    .class_init = escc_class_init,
+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 71d3e70..2f44386 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -759,23 +759,25 @@ static Property esp_properties[] = {
 
 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 DeviceInfo esp_info = {
-    .name = "esp",
-    .size = sizeof(ESPState),
-    .vmsd = &vmstate_esp,
-    .reset = esp_hard_reset,
-    .props = esp_properties,
-    .class_init = esp_class_init,
+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 92c822b..aefd577 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -623,21 +623,23 @@ static Property etraxfs_eth_properties[] = {
 
 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 DeviceInfo etraxfs_eth_info = {
-    .name = "etraxfs-eth",
-    .size = sizeof(struct fs_eth),
-    .props = etraxfs_eth_properties,
-    .class_init = etraxfs_eth_class_init,
+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 8acf01e..33541fc 100644
--- a/hw/etraxfs_pic.c
+++ b/hw/etraxfs_pic.c
@@ -158,21 +158,23 @@ static Property etraxfs_pic_properties[] = {
 
 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 DeviceInfo etraxfs_pic_info = {
-    .name = "etraxfs,pic",
-    .size = sizeof(struct etrax_pic),
-    .props = etraxfs_pic_properties,
-    .class_init = etraxfs_pic_class_init,
+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 a487805..b8acd43 100644
--- a/hw/etraxfs_ser.c
+++ b/hw/etraxfs_ser.c
@@ -226,21 +226,23 @@ static int etraxfs_ser_init(SysBusDevice *dev)
 
 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 DeviceInfo etraxfs_ser_info = {
-    .name = "etraxfs,serial",
-    .size = sizeof(struct etrax_serial),
-    .reset = etraxfs_ser_reset,
-    .class_init = etraxfs_ser_class_init,
+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 c33058c..b71c5ee 100644
--- a/hw/etraxfs_timer.c
+++ b/hw/etraxfs_timer.c
@@ -336,15 +336,16 @@ static void etraxfs_timer_class_init(ObjectClass *klass, void *data)
     sdc->init = etraxfs_timer_init;
 }
 
-static DeviceInfo etraxfs_timer_info = {
-    .name = "etraxfs,timer",
-    .size = sizeof (struct etrax_timer),
-    .class_init = etraxfs_timer_class_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_qdev_register(&etraxfs_timer_info);
+    type_register_static(&etraxfs_timer_info);
 }
 
 device_init(etraxfs_timer_register)
diff --git a/hw/fdc.c b/hw/fdc.c
index 8562284..f575a2c 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1959,27 +1959,31 @@ static const VMStateDescription vmstate_isa_fdc ={
     }
 };
 
+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;
-}
-
-static DeviceInfo isa_fdc_info = {
-    .class_init = isabus_fdc_class_init1,
-    .name  = "isa-fdc",
-    .fw_name  = "fdc",
-    .size  = sizeof(FDCtrlISABus),
-    .no_user = 1,
-    .vmsd  = &vmstate_isa_fdc,
-    .reset = fdctrl_external_reset_isa,
-    .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(),
-    },
+    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 ={
@@ -2000,18 +2004,20 @@ static Property sysbus_fdc_properties[] = {
 
 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 DeviceInfo sysbus_fdc_info = {
-    .name = "sysbus-fdc",
-    .size = sizeof(FDCtrlSysBus),
-    .vmsd = &vmstate_sysbus_fdc,
-    .reset = fdctrl_external_reset_sysbus,
-    .props = sysbus_fdc_properties,
-    .class_init = sysbus_fdc_class_init,
+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[] = {
@@ -2021,25 +2027,27 @@ static Property sun4m_fdc_properties[] = {
 
 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 DeviceInfo sun4m_fdc_info = {
-    .name = "SUNW,fdtwo",
-    .size = sizeof(FDCtrlSysBus),
-    .vmsd = &vmstate_sysbus_fdc,
-    .reset = fdctrl_external_reset_sysbus,
-    .props = sun4m_fdc_properties,
-    .class_init = sun4m_fdc_class_init,
+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/fw_cfg.c b/hw/fw_cfg.c
index e669ed4..6b2f7d1 100644
--- a/hw/fw_cfg.c
+++ b/hw/fw_cfg.c
@@ -539,24 +539,26 @@ static Property fw_cfg_properties[] = {
 
 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 DeviceInfo fw_cfg_info = {
-    .name = "fw_cfg",
-    .size = sizeof(FWCfgState),
-    .vmsd = &vmstate_fw_cfg,
-    .reset = fw_cfg_reset,
-    .no_user = 1,
-    .props = fw_cfg_properties,
-    .class_init = fw_cfg_class_init,
+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 82b31f7..f47acc5 100644
--- a/hw/g364fb.c
+++ b/hw/g364fb.c
@@ -556,24 +556,26 @@ static Property g364fb_sysbus_properties[] = {
 
 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 DeviceInfo g364fb_sysbus_info = {
-    .name = "sysbus-g364",
-    .desc = "G364 framebuffer",
-    .size = sizeof(G364SysBusState),
-    .vmsd = &vmstate_g364fb,
-    .reset = g364fb_sysbus_reset,
-    .props = g364fb_sysbus_properties,
-    .class_init = g364fb_sysbus_class_init,
+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 549859d..8122baf 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -124,39 +124,43 @@ static int grackle_pci_host_init(PCIDevice *d)
 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 DeviceInfo grackle_pci_info = {
-    .name = "grackle",
-    .size = sizeof(PCIDevice),
-    .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 DeviceInfo grackle_pci_host_info = {
-    .name = "grackle-pcihost",
-    .size = sizeof(GrackleState),
-    .no_user = 1,
-    .class_init = pci_grackle_class_init,
+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_qdev_register(&grackle_pci_host_info);
-    pci_qdev_register(&grackle_pci_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 f7755b0..89de2d8 100644
--- a/hw/grlib_apbuart.c
+++ b/hw/grlib_apbuart.c
@@ -249,21 +249,23 @@ static Property grlib_gptimer_properties[] = {
 
 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 DeviceInfo grlib_gptimer_info = {
-    .name = "grlib,apbuart",
-    .size = sizeof(UART),
-    .props = grlib_gptimer_properties,
-    .class_init = grlib_gptimer_class_init,
+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 219009e..fb0b236 100644
--- a/hw/grlib_gptimer.c
+++ b/hw/grlib_gptimer.c
@@ -381,22 +381,24 @@ static Property grlib_gptimer_properties[] = {
 
 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 DeviceInfo grlib_gptimer_info = {
-    .name = "grlib,gptimer",
-    .reset = grlib_gptimer_reset,
-    .size = sizeof(GPTimerUnit),
-    .props = grlib_gptimer_properties,
-    .class_init = grlib_gptimer_class_init,
+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 1ccddfb..1e5ad82 100644
--- a/hw/grlib_irqmp.c
+++ b/hw/grlib_irqmp.c
@@ -362,22 +362,24 @@ static Property grlib_irqmp_properties[] = {
 
 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 DeviceInfo grlib_irqmp_info = {
-    .name = "grlib,irqmp",
-    .reset = grlib_irqmp_reset,
-    .size = sizeof(IRQMP),
-    .props = grlib_irqmp_properties,
-    .class_init = grlib_irqmp_class_init,
+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 79d2dfb..e8cd59c 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -1147,10 +1147,11 @@ static void gt64120_pci_class_init(ObjectClass *klass, void *data)
     k->class_id = PCI_CLASS_BRIDGE_HOST;
 }
 
-static DeviceInfo gt64120_pci_info = {
-    .name = "gt64120_pci",
-    .size = sizeof(PCIDevice),
-    .class_init = gt64120_pci_class_init,
+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)
@@ -1160,16 +1161,17 @@ static void gt64120_class_init(ObjectClass *klass, void *data)
     sdc->init = gt64120_init;
 }
 
-static DeviceInfo gt64120_info = {
-    .name = "gt64120",
-    .size = sizeof(GT64120State),
-    .class_init = gt64120_class_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_qdev_register(&gt64120_info);
-    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 6603aab..49e5dbf 100644
--- a/hw/gus.c
+++ b/hw/gus.c
@@ -299,29 +299,33 @@ int GUS_init (ISABus *bus)
     return 0;
 }
 
+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 DeviceInfo gus_info = {
-    .name     = "gus",
-    .desc     = "Gravis Ultrasound GF1",
-    .size     = sizeof (GUSState),
-    .vmsd     = &vmstate_gus,
-    .class_init          = gus_class_initfn,
-    .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 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 2b3ce2f..152f8e6 100644
--- a/hw/hda-audio.c
+++ b/hw/hda-audio.c
@@ -908,45 +908,49 @@ static int hda_audio_init_duplex(HDACodecDevice *hda)
 
 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 DeviceInfo hda_audio_output_info = {
-    .name = "hda-output",
-    .desc = "HDA Audio Codec, output-only",
-    .size = sizeof(HDAAudioState),
-    .vmsd = &vmstate_hda_audio,
-    .props = hda_audio_properties,
-    .class_init = hda_audio_output_class_init,
+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 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 DeviceInfo hda_audio_duplex_info = {
-    .name = "hda-duplex",
-    .desc = "HDA Audio Codec, duplex",
-    .size = sizeof(HDAAudioState),
-    .vmsd = &vmstate_hda_audio,
-    .props = hda_audio_properties,
-    .class_init = hda_audio_duplex_class_init,
+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_output_info);
-    hda_codec_register(&hda_audio_duplex_info);
+    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
index 9f76716..684178e 100644
--- a/hw/highbank.c
+++ b/hw/highbank.c
@@ -162,22 +162,24 @@ static int highbank_regs_init(SysBusDevice *dev)
 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 DeviceInfo highbank_regs_info = {
-    .name  = "highbank-regs",
-    .desc  = "Calxeda Highbank registers",
-    .size  = sizeof(HighbankRegsState),
-    .vmsd  = &vmstate_highbank_regs,
-    .class_init = highbank_regs_class_init,
-    .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)
 {
-    sysbus_qdev_register(&highbank_regs_info);
+    type_register_static(&highbank_regs_info);
 }
 
 device_init(highbank_regs_register_device)
diff --git a/hw/hpet.c b/hw/hpet.c
index aba9ea9..b6ace4e 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -703,24 +703,26 @@ static Property hpet_device_properties[] = {
 
 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 DeviceInfo hpet_device_info = {
-    .name = "hpet",
-    .size = sizeof(HPETState),
-    .no_user = 1,
-    .vmsd = &vmstate_hpet,
-    .reset = hpet_reset,
-    .props = hpet_device_properties,
-    .class_init = hpet_device_class_init,
+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 9e5d3df..e21a666 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -204,19 +204,6 @@ static int i2c_slave_qdev_init(DeviceState *dev, DeviceInfo *base)
     return sc->init(s);
 }
 
-void i2c_register_slave_subclass(DeviceInfo *info, const char *parent)
-{
-    assert(info->size >= sizeof(I2CSlave));
-    info->init = i2c_slave_qdev_init;
-    info->bus_info = &i2c_bus_info;
-    qdev_register_subclass(info, parent);
-}
-
-void i2c_register_slave(DeviceInfo *info)
-{
-    i2c_register_slave_subclass(info, TYPE_I2C_SLAVE);
-}
-
 DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr)
 {
     DeviceState *dev;
@@ -227,12 +214,20 @@ DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr)
     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)
diff --git a/hw/i2c.h b/hw/i2c.h
index 31fd59c..0f5682b 100644
--- a/hw/i2c.h
+++ b/hw/i2c.h
@@ -62,9 +62,6 @@ int i2c_recv(i2c_bus *bus);
 #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(DeviceInfo *type);
-void i2c_register_slave_subclass(DeviceInfo *info, const char *parent);
-
 DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr);
 
 /* wm8750.c */
diff --git a/hw/i82374.c b/hw/i82374.c
index 2814379..220e8cc 100644
--- a/hw/i82374.c
+++ b/hw/i82374.c
@@ -135,27 +135,31 @@ static int i82374_isa_init(ISADevice *dev)
     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;
+    k->init  = i82374_isa_init;
+    dc->vmsd = &vmstate_isa_i82374;
+    dc->props = i82374_properties;
 }
 
-static DeviceInfo i82374_isa_info = {
+static TypeInfo i82374_isa_info = {
     .name  = "i82374",
-    .size  = sizeof(ISAi82374State),
-    .vmsd  = &vmstate_isa_i82374,
+    .parent = TYPE_ISA_DEVICE,
+    .instance_size  = sizeof(ISAi82374State),
     .class_init = i82374_class_init,
-    .props = (Property[]) {
-        DEFINE_PROP_HEX32("iobase", ISAi82374State, iobase, 0x400),
-        DEFINE_PROP_END_OF_LIST()
-    },
 };
 
 static void i82374_register_devices(void)
 {
-    isa_qdev_register(&i82374_isa_info);
+    type_register_static(&i82374_isa_info);
 }
 
 device_init(i82374_register_devices)
diff --git a/hw/i82378.c b/hw/i82378.c
index 99b453a..9c3efe8 100644
--- a/hw/i82378.c
+++ b/hw/i82378.c
@@ -238,9 +238,16 @@ static int pci_i82378_init(PCIDevice *dev)
     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;
@@ -249,23 +256,20 @@ static void pci_i82378_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo pci_i82378_info = {
+static TypeInfo pci_i82378_info = {
     .name = "i82378",
-    .size = sizeof(PCIi82378State),
-    .vmsd = &vmstate_pci_i82378,
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIi82378State),
     .class_init = pci_i82378_class_init,
-    .props = (Property[]) {
-        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 i82378_register_devices(void)
 {
-    pci_qdev_register(&pci_i82378_info);
+    type_register_static(&pci_i82378_info);
 }
 
 device_init(i82378_register_devices)
diff --git a/hw/i8254.c b/hw/i8254.c
index add1fab..522fed8 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -535,28 +535,32 @@ static int pit_initfn(ISADevice *dev)
     return 0;
 }
 
+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 DeviceInfo pit_info = {
-    .name     = "isa-pit",
-    .size     = sizeof(PITState),
-    .vmsd     = &vmstate_pit,
-    .reset    = pit_reset,
-    .no_user  = 1,
-    .class_init          = pit_class_initfn,
-    .props = (Property[]) {
-        DEFINE_PROP_UINT32("irq", PITState, irq,  -1),
-        DEFINE_PROP_HEX32("iobase", PITState, iobase,  -1),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+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 e083bb6..7ae5380 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -475,19 +475,22 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
 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 DeviceInfo i8259_info = {
-    .name  = "isa-i8259",
-    .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)
 {
-    pic_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
index 24b1076..9f150bc 100644
--- a/hw/i8259_common.c
+++ b/hw/i8259_common.c
@@ -133,19 +133,14 @@ static Property pic_properties_common[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
-void pic_qdev_register(DeviceInfo *info)
-{
-    info->size = sizeof(PICCommonState);
-    info->vmsd = &vmstate_pic_common;
-    info->no_user = 1;
-    info->props = pic_properties_common;
-    isa_qdev_register_subclass(info, TYPE_PIC_COMMON);
-}
-
 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;
 }
 
diff --git a/hw/i8259_internal.h b/hw/i8259_internal.h
index e9d1732..4137b61 100644
--- a/hw/i8259_internal.h
+++ b/hw/i8259_internal.h
@@ -78,6 +78,5 @@ void pic_reset_common(PICCommonState *s);
 
 ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master);
 
-void pic_qdev_register(DeviceInfo *info);
 
 #endif /* !QEMU_I8259_INTERNAL_H */
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 8869fd6..c87a6ca 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -1239,27 +1239,31 @@ static int sysbus_ahci_init(SysBusDevice *dev)
     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 DeviceInfo sysbus_ahci_info = {
-    .name    = "sysbus-ahci",
-    .size    = sizeof(SysbusAHCIState),
-    .vmsd    = &vmstate_sysbus_ahci,
-    .class_init = sysbus_ahci_class_init,
-    .props = (Property[]) {
-        DEFINE_PROP_UINT32("num-ports", SysbusAHCIState, num_ports, 1),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+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)
 {
-    sysbus_qdev_register(&sysbus_ahci_info);
+    type_register_static(&sysbus_ahci_info);
 }
 
 device_init(sysbus_ahci_register);
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 9c673bb..a119500 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -332,6 +332,7 @@ static Property cmd646_ide_properties[] = {
 
 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;
@@ -340,17 +341,18 @@ static void cmd646_ide_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_CMD_646;
     k->revision = 0x07;
     k->class_id = PCI_CLASS_STORAGE_IDE;
+    dc->props = cmd646_ide_properties;
 }
 
-static DeviceInfo cmd646_ide_info = {
-    .name = "cmd646-ide",
-    .size = sizeof(PCIIDEState),
-    .props = cmd646_ide_properties,
-    .class_init = cmd646_ide_class_init,
+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(&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 1cae9f1..0e819f6 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -148,6 +148,7 @@ static void pci_ich9_write_config(PCIDevice *pci, uint32_t addr,
 
 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;
@@ -157,18 +158,20 @@ static void ich_ahci_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_INTEL_82801IR;
     k->revision = 0x02;
     k->class_id = PCI_CLASS_STORAGE_SATA;
+    dc->alias = "ahci";
+    dc->vmsd = &vmstate_ahci;
 }
 
-static DeviceInfo ich_ahci_info = {
-    .name = "ich9-ahci",
-    .alias = "ahci",
-    .size = sizeof(AHCIPCIState),
-    .vmsd = &vmstate_ahci,
-    .class_init = ich_ahci_class_init,
+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(&ich_ahci_info);
+    type_register_static(&ich_ahci_info);
+    type_register_static_alias(&ich_ahci_info, "ahci");
 }
 device_init(ich_ahci_register);
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 464473a..a0bcb43 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -94,29 +94,33 @@ ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq,
     return dev;
 }
 
+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 DeviceInfo isa_ide_info = {
-    .name  = "isa-ide",
-    .fw_name  = "ide",
-    .size  = sizeof(ISAIDEState),
-    .class_init       = isa_ide_class_initfn,
-    .reset = isa_ide_reset,
-    .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 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/piix.c b/hw/ide/piix.c
index 832a507..bf4465b 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -239,6 +239,7 @@ PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
 
 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;
@@ -247,35 +248,39 @@ static void piix3_ide_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo piix3_ide_info = {
-    .name = "piix3-ide",
-    .size = sizeof(PCIIDEState),
-    .no_user = 1,
-    .class_init = piix3_ide_class_init,
+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 DeviceInfo piix3_ide_xen_info = {
-    .name = "piix3-ide-xen",
-    .size = sizeof(PCIIDEState),
-    .no_user = 1,
-    .class_init = piix3_ide_xen_class_init,
-    .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;
@@ -284,19 +289,20 @@ static void piix4_ide_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo piix4_ide_info = {
-    .name = "piix4-ide",
-    .size = sizeof(PCIIDEState),
-    .no_user = 1,
-    .class_init = piix4_ide_class_init,
+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(&piix3_ide_info);
-    pci_qdev_register(&piix3_ide_xen_info);
-    pci_qdev_register(&piix4_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 b507e34..1335615 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -91,13 +91,6 @@ err:
     return -1;
 }
 
-static void ide_qdev_register(DeviceInfo *info)
-{
-    info->init = ide_qdev_init;
-    info->bus_info = &ide_bus_info;
-    qdev_register_subclass(info, TYPE_IDE_DEVICE);
-}
-
 IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive)
 {
     DeviceState *dev;
@@ -182,73 +175,93 @@ static int ide_drive_initfn(IDEDevice *dev)
     DEFINE_PROP_STRING("ver",  IDEDrive, dev.version),  \
     DEFINE_PROP_STRING("serial",  IDEDrive, dev.serial)
 
+static Property ide_hd_properties[] = {
+    DEFINE_IDE_DEV_PROPERTIES(),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
 static void ide_hd_class_init(ObjectClass *klass, void *data)
 {
+    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;
 }
 
-static DeviceInfo ide_hd_info = {
-    .name    = "ide-hd",
-    .fw_name = "drive",
-    .desc    = "virtual IDE disk",
-    .size    = sizeof(IDEDrive),
-    .class_init = ide_hd_class_init,
-    .props   = (Property[]) {
-        DEFINE_IDE_DEV_PROPERTIES(),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+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 DeviceInfo ide_cd_info = {
-    .name    = "ide-cd",
-    .fw_name = "drive",
-    .desc    = "virtual IDE CD-ROM",
-    .size    = sizeof(IDEDrive),
-    .class_init = ide_cd_class_init,
-    .props   = (Property[]) {
-        DEFINE_IDE_DEV_PROPERTIES(),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+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 DeviceInfo ide_drive_info = {
-    .name    = "ide-drive", /* legacy -device ide-drive */
-    .fw_name = "drive",
-    .desc    = "virtual IDE disk or CD-ROM (legacy)",
-    .size    = sizeof(IDEDrive),
-    .class_init = ide_drive_class_init,
-    .props   = (Property[]) {
-        DEFINE_IDE_DEV_PROPERTIES(),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+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)
 {
-    ide_qdev_register(&ide_hd_info);
-    ide_qdev_register(&ide_cd_info);
-    ide_qdev_register(&ide_drive_info);
+    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 ef70864..b4ca6f2 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -215,6 +215,7 @@ void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
 
 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;
@@ -223,17 +224,18 @@ static void via_ide_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_VIA_IDE;
     k->revision = 0x06;
     k->class_id = PCI_CLASS_STORAGE_IDE;
+    dc->no_user = 1;
 }
 
-static DeviceInfo via_ide_info = {
-    .name = "via-ide",
-    .size = sizeof(PCIIDEState),
-    .no_user = 1,
-    .class_init = via_ide_class_init,
+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 130accf..6dbd649 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -525,16 +525,18 @@ static Property core_properties[] = {
 
 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 DeviceInfo core_info = {
-    .name = "integrator_core",
-    .size = sizeof(integratorcm_state),
-    .props = core_properties,
-    .class_init = core_class_init,
+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)
@@ -544,16 +546,17 @@ static void icp_pic_class_init(ObjectClass *klass, void *data)
     sdc->init = icp_pic_init;
 }
 
-static DeviceInfo icp_pic_info = {
-    .name = "integrator_pic",
-    .size = sizeof(icp_pic_state),
-    .class_init = icp_pic_class_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_qdev_register(&icp_pic_info);
-    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 f062133..9e4a31f 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -74,14 +74,6 @@ static int hda_codec_dev_exit(DeviceState *qdev)
     return 0;
 }
 
-void hda_codec_register(DeviceInfo *info)
-{
-    info->init = hda_codec_dev_init;
-    info->exit = hda_codec_dev_exit;
-    info->bus_info = &hda_codec_bus_info;
-    qdev_register_subclass(info, TYPE_HDA_CODEC_DEVICE);
-}
-
 HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
 {
     DeviceState *qdev;
@@ -1255,6 +1247,7 @@ static Property intel_hda_properties[] = {
 
 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;
@@ -1264,29 +1257,39 @@ static void intel_hda_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo intel_hda_info = {
-    .name = "intel-hda",
-    .desc = "Intel HD Audio Controller",
-    .size = sizeof(IntelHDAState),
-    .vmsd = &vmstate_intel_hda,
-    .reset = intel_hda_reset,
-    .props = intel_hda_properties,
-    .class_init = intel_hda_class_init,
+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 f523587..a1cca5b 100644
--- a/hw/intel-hda.h
+++ b/hw/intel-hda.h
@@ -48,7 +48,6 @@ struct HDACodecDevice {
 void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
                         hda_codec_response_func response,
                         hda_codec_xfer_func xfer);
-void hda_codec_register(DeviceInfo *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 0939009..79549f8 100644
--- a/hw/ioapic.c
+++ b/hw/ioapic.c
@@ -238,20 +238,22 @@ static void ioapic_init(IOAPICCommonState *s, int instance_no)
 static void ioapic_class_init(ObjectClass *klass, void *data)
 {
     IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
 
     k->init = ioapic_init;
+    dc->reset = ioapic_reset_common;
 }
 
-static DeviceInfo ioapic_info = {
-    .name = "ioapic",
-    .size = sizeof(IOAPICCommonState),
-    .reset = ioapic_reset_common,
-    .class_init = ioapic_class_init,
+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)
 {
-    ioapic_qdev_register(&ioapic_info);
+    type_register_static(&ioapic_info);
 }
 
 device_init(ioapic_register_devices)
diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c
index 4bb7ea9..f932700 100644
--- a/hw/ioapic_common.c
+++ b/hw/ioapic_common.c
@@ -96,8 +96,11 @@ static const VMStateDescription vmstate_ioapic_common = {
 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 = {
@@ -109,13 +112,6 @@ static TypeInfo ioapic_common_type = {
     .abstract = true,
 };
 
-void ioapic_qdev_register(DeviceInfo *info)
-{
-    info->vmsd = &vmstate_ioapic_common;
-    info->no_user = 1;
-    sysbus_qdev_register_subclass(info, TYPE_IOAPIC_COMMON);
-}
-
 static void register_devices(void)
 {
     type_register_static(&ioapic_common_type);
diff --git a/hw/ioapic_internal.h b/hw/ioapic_internal.h
index 9dff1a7..e04c9f3 100644
--- a/hw/ioapic_internal.h
+++ b/hw/ioapic_internal.h
@@ -97,7 +97,6 @@ struct IOAPICCommonState {
     uint64_t ioredtbl[IOAPIC_NUM_PINS];
 };
 
-void ioapic_qdev_register(DeviceInfo *info);
 void ioapic_reset_common(DeviceState *dev);
 
 #endif /* !QEMU_IOAPIC_INTERNAL_H */
diff --git a/hw/ioh3420.c b/hw/ioh3420.c
index 6cfafb3..1c60123 100644
--- a/hw/ioh3420.c
+++ b/hw/ioh3420.c
@@ -213,6 +213,7 @@ static Property ioh3420_properties[] = {
 
 static void ioh3420_class_init(ObjectClass *klass, void *data)
 {
+    DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
     k->is_express = 1;
@@ -223,21 +224,22 @@ static void ioh3420_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo ioh3420_info = {
-    .name = "ioh3420",
-    .desc = "Intel IOH device id 3420 PCIE Root Port",
-    .size = sizeof(PCIESlot),
-    .reset = ioh3420_reset,
-    .vmsd = &vmstate_ioh3420,
-    .props = ioh3420_properties,
-    .class_init = ioh3420_class_init,
+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 92d8882..a22c5c6 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -125,18 +125,6 @@ static int isa_qdev_init(DeviceState *qdev, DeviceInfo *base)
     return 0;
 }
 
-void isa_qdev_register_subclass(DeviceInfo *info, const char *parent)
-{
-    info->init = isa_qdev_init;
-    info->bus_info = &isa_bus_info;
-    qdev_register_subclass(info, parent);
-}
-
-void isa_qdev_register(DeviceInfo *info)
-{
-    isa_qdev_register_subclass(info, TYPE_ISA_DEVICE);
-}
-
 ISADevice *isa_create(ISABus *bus, const char *name)
 {
     DeviceState *dev;
@@ -191,30 +179,40 @@ static int isabus_bridge_init(SysBusDevice *dev)
 
 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 DeviceInfo isabus_bridge_info = {
-    .name = "isabus-bridge",
-    .fw_name = "isa",
-    .size = sizeof(SysBusDevice),
-    .no_user = 1,
-    .class_init = isabus_bridge_class_init,
+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);
 }
 
diff --git a/hw/isa.h b/hw/isa.h
index 9f5d158..40373fb 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -41,8 +41,6 @@ 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(DeviceInfo *info);
-void isa_qdev_register_subclass(DeviceInfo *info, const char *parent);
 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 e2880be..6f017d4 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -779,6 +779,7 @@ static Property ivshmem_properties[] = {
 
 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;
@@ -786,19 +787,20 @@ static void ivshmem_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo ivshmem_info = {
-    .name = "ivshmem",
-    .size = sizeof(IVShmemState),
-    .reset = ivshmem_reset,
-    .props = ivshmem_properties,
-    .class_init = ivshmem_class_init,
+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
index bc80ae4..89e33b0 100644
--- a/hw/kvm/apic.c
+++ b/hw/kvm/apic.c
@@ -132,14 +132,15 @@ static void kvm_apic_class_init(ObjectClass *klass, void *data)
     k->external_nmi = kvm_apic_external_nmi;
 }
 
-static DeviceInfo kvm_apic_info = {
+static TypeInfo kvm_apic_info = {
     .name = "kvm-apic",
+    .parent = TYPE_APIC_COMMON,
     .class_init = kvm_apic_class_init,
 };
 
 static void kvm_apic_register_device(void)
 {
-    apic_qdev_register(&kvm_apic_info);
+    type_register_static(&kvm_apic_info);
 }
 
 device_init(kvm_apic_register_device)
diff --git a/hw/kvm/clock.c b/hw/kvm/clock.c
index b997d2a..d5a5386 100644
--- a/hw/kvm/clock.c
+++ b/hw/kvm/clock.c
@@ -94,17 +94,19 @@ static const VMStateDescription kvmclock_vmsd = {
 
 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 DeviceInfo kvmclock_info = {
-    .name = "kvmclock",
-    .size = sizeof(KVMClockState),
-    .vmsd = &kvmclock_vmsd,
-    .no_user = 1,
-    .class_init = kvmclock_class_init,
+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. */
@@ -120,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/kvm/i8259.c b/hw/kvm/i8259.c
index b34901c..297d64e 100644
--- a/hw/kvm/i8259.c
+++ b/hw/kvm/i8259.c
@@ -115,21 +115,23 @@ qemu_irq *kvm_i8259_init(ISABus *bus)
 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 DeviceInfo kvm_i8259_info = {
+static TypeInfo kvm_i8259_info = {
     .name  = "kvm-i8259",
-    .reset = kvm_pic_reset,
+    .parent = TYPE_PIC_COMMON,
     .class_init = kvm_i8259_class_init,
 };
 
 static void kvm_pic_register(void)
 {
-    pic_qdev_register(&kvm_i8259_info);
+    type_register_static(&kvm_i8259_info);
 }
 
 device_init(kvm_pic_register)
diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c
index f8ea0cc..b316933 100644
--- a/hw/kvm/ioapic.c
+++ b/hw/kvm/ioapic.c
@@ -93,29 +93,33 @@ static void kvm_ioapic_init(IOAPICCommonState *s, int instance_no)
     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 DeviceInfo kvm_ioapic_info = {
+static TypeInfo kvm_ioapic_info = {
     .name  = "kvm-ioapic",
-    .size = sizeof(KVMIOAPICState),
-    .reset = kvm_ioapic_reset,
+    .parent = TYPE_IOAPIC_COMMON,
+    .instance_size = sizeof(KVMIOAPICState),
     .class_init = kvm_ioapic_class_init,
-    .props = (Property[]) {
-        DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0),
-        DEFINE_PROP_END_OF_LIST()
-    },
 };
 
 static void kvm_ioapic_register_device(void)
 {
-    ioapic_qdev_register(&kvm_ioapic_info);
+    type_register_static(&kvm_ioapic_info);
 }
 
 device_init(kvm_ioapic_register_device)
diff --git a/hw/lan9118.c b/hw/lan9118.c
index 3925b04..78777c7 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -1245,23 +1245,25 @@ static Property lan9118_properties[] = {
 
 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 DeviceInfo lan9118_info = {
-    .name = "lan9118",
-    .size = sizeof(lan9118_state),
-    .reset = lan9118_reset,
-    .vmsd = &vmstate_lan9118,
-    .props = lan9118_properties,
-    .class_init = lan9118_class_init,
+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 969d766..519720b 100644
--- a/hw/lance.c
+++ b/hw/lance.c
@@ -145,23 +145,25 @@ static Property lance_properties[] = {
 
 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 DeviceInfo lance_info = {
-    .name = "lance",
-    .fw_name = "ethernet",
-    .size = sizeof(SysBusPCNetState),
-    .reset = lance_reset,
-    .vmsd = &vmstate_lance,
-    .props = lance_properties,
-    .class_init = lance_class_init,
+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 e25a409..023c644 100644
--- a/hw/lm32_juart.c
+++ b/hw/lm32_juart.c
@@ -136,22 +136,24 @@ static const VMStateDescription vmstate_lm32_juart = {
 
 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 DeviceInfo lm32_juart_info = {
-    .name = "lm32-juart",
-    .size = sizeof(LM32JuartState),
-    .vmsd = &vmstate_lm32_juart,
-    .reset = juart_reset,
-    .class_init = lm32_juart_class_init,
+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 b7b1886..7be6d0d 100644
--- a/hw/lm32_pic.c
+++ b/hw/lm32_pic.c
@@ -176,22 +176,24 @@ static const VMStateDescription vmstate_lm32_pic = {
 
 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 DeviceInfo lm32_pic_info = {
-    .name = "lm32-pic",
-    .size = sizeof(LM32PicState),
-    .vmsd = &vmstate_lm32_pic,
-    .reset = pic_reset,
-    .class_init = lm32_pic_class_init,
+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 c83809e..ba6f4ac 100644
--- a/hw/lm32_sys.c
+++ b/hw/lm32_sys.c
@@ -148,23 +148,25 @@ static Property lm32_sys_properties[] = {
 
 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 DeviceInfo lm32_sys_info = {
-    .name = "lm32-sys",
-    .size = sizeof(LM32SysState),
-    .vmsd = &vmstate_lm32_sys,
-    .reset = sys_reset,
-    .props = lm32_sys_properties,
-    .class_init = lm32_sys_class_init,
+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 932c1f0..3cb4e0a 100644
--- a/hw/lm32_timer.c
+++ b/hw/lm32_timer.c
@@ -206,23 +206,25 @@ static Property lm32_timer_properties[] = {
 
 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 DeviceInfo lm32_timer_info = {
-    .name = "lm32-timer",
-    .size = sizeof(LM32TimerState),
-    .vmsd = &vmstate_lm32_timer,
-    .reset = timer_reset,
-    .props = lm32_timer_properties,
-    .class_init = lm32_timer_class_init,
+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 ea7d00e..fc70490 100644
--- a/hw/lm32_uart.c
+++ b/hw/lm32_uart.c
@@ -273,22 +273,24 @@ static const VMStateDescription vmstate_lm32_uart = {
 
 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 DeviceInfo lm32_uart_info = {
-    .name = "lm32-uart",
-    .size = sizeof(LM32UartState),
-    .vmsd = &vmstate_lm32_uart,
-    .reset = uart_reset,
-    .class_init = lm32_uart_class_init,
+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 84f81fe..895d306 100644
--- a/hw/lm832x.c
+++ b/hw/lm832x.c
@@ -496,24 +496,26 @@ void lm832x_key_event(DeviceState *dev, int key, int state)
 
 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 DeviceInfo lm8323_info = {
-    .name = "lm8323",
-    .size = sizeof(LM823KbdState),
-    .vmsd = &vmstate_lm_kbd,
-    .class_init = lm8323_class_init,
+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/lsi53c895a.c b/hw/lsi53c895a.c
index 3571588..638332e 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -2122,6 +2122,7 @@ static int lsi_scsi_init(PCIDevice *dev)
 
 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;
@@ -2130,20 +2131,22 @@ static void lsi_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_LSI_53C895A;
     k->class_id = PCI_CLASS_STORAGE_SCSI;
     k->subsystem_id = 0x1000;
+    dc->alias = "lsi";
+    dc->reset = lsi_scsi_reset;
+    dc->vmsd = &vmstate_lsi_scsi;
 }
 
-static DeviceInfo lsi_info = {
-    .name = "lsi53c895a",
-    .alias = "lsi",
-    .size = sizeof(LSIState),
-    .reset = lsi_scsi_reset,
-    .vmsd = &vmstate_lsi_scsi,
-    .class_init = lsi_class_init,
+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);
+    type_register_static_alias(&lsi_info, "lsi");
 }
 
 device_init(lsi53c895a_register_devices);
diff --git a/hw/m48t59.c b/hw/m48t59.c
index bd610f0..c35867d 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -720,24 +720,28 @@ static int m48t59_init1(SysBusDevice *dev)
     return 0;
 }
 
+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 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 DeviceInfo m48t59_isa_info = {
-    .class_init = m48t59_init_class_isa1,
-    .name = "m48t59_isa",
-    .size = sizeof(M48t59ISAState),
-    .reset = m48t59_reset_isa,
-    .no_user = 1,
-    .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 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[] = {
@@ -749,23 +753,25 @@ static Property m48t59_properties[] = {
 
 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 DeviceInfo m48t59_info = {
-    .name = "m48t59",
-    .size = sizeof(M48t59SysBusState),
-    .reset = m48t59_reset_sysbus,
-    .props = m48t59_properties,
-    .class_init = m48t59_class_init,
+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 ae9db08..3d648e9 100644
--- a/hw/macio.c
+++ b/hw/macio.c
@@ -90,15 +90,16 @@ static void macio_class_init(ObjectClass *klass, void *data)
     k->class_id = PCI_CLASS_OTHERS << 8;
 }
 
-static DeviceInfo macio_info = {
-    .name = "macio",
-    .size = sizeof(MacIOState),
-    .class_init = macio_class_init,
+static TypeInfo macio_info = {
+    .name          = "macio",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(MacIOState),
+    .class_init    = macio_class_init,
 };
 
 static void macio_register(void)
 {
-    pci_qdev_register(&macio_info);
+    type_register_static(&macio_info);
 }
 
 device_init(macio_register);
diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c
index 355e492..b628f17 100644
--- a/hw/marvell_88w8618_audio.c
+++ b/hw/marvell_88w8618_audio.c
@@ -279,23 +279,25 @@ static Property mv88w8618_audio_properties[] = {
 
 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 DeviceInfo mv88w8618_audio_info = {
-    .name = "mv88w8618_audio",
-    .size = sizeof(mv88w8618_audio_state),
-    .reset = mv88w8618_audio_reset,
-    .vmsd = &mv88w8618_audio_vmsd,
-    .props = mv88w8618_audio_properties,
-    .class_init = mv88w8618_audio_class_init,
+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 db17842..9d61aa9 100644
--- a/hw/max111x.c
+++ b/hw/max111x.c
@@ -161,10 +161,11 @@ static void max1110_class_init(ObjectClass *klass, void *data)
     k->transfer = max111x_transfer;
 }
 
-static DeviceInfo max1110_info = {
-    .name = "max1110",
-    .size = sizeof(MAX111xState),
-    .class_init = max1110_class_init,
+static TypeInfo max1110_info = {
+    .name          = "max1110",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(MAX111xState),
+    .class_init    = max1110_class_init,
 };
 
 static void max1111_class_init(ObjectClass *klass, void *data)
@@ -175,16 +176,17 @@ static void max1111_class_init(ObjectClass *klass, void *data)
     k->transfer = max111x_transfer;
 }
 
-static DeviceInfo max1111_info = {
-    .name = "max1111",
-    .size = sizeof(MAX111xState),
-    .class_init = max1111_class_init,
+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 0cc3219..3a6bb96 100644
--- a/hw/max7310.c
+++ b/hw/max7310.c
@@ -187,25 +187,27 @@ static int max7310_init(I2CSlave *i2c)
 
 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 DeviceInfo max7310_info = {
-    .name = "max7310",
-    .size = sizeof(MAX7310State),
-    .vmsd = &vmstate_max7310,
-    .reset = max7310_reset,
-    .class_init = max7310_class_init,
+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 e6e4cb7..cbbf1f0 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -709,28 +709,32 @@ ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq)
     return dev;
 }
 
+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 DeviceInfo mc146818rtc_info = {
-    .name     = "mc146818rtc",
-    .size     = sizeof(RTCState),
-    .no_user  = 1,
-    .vmsd     = &vmstate_rtc,
-    .class_init          = rtc_class_initfn,
-    .props    = (Property[]) {
-        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 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 7dce5bc..0881643 100644
--- a/hw/milkymist-ac97.c
+++ b/hw/milkymist-ac97.c
@@ -321,22 +321,24 @@ static const VMStateDescription vmstate_milkymist_ac97 = {
 
 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 DeviceInfo milkymist_ac97_info = {
-    .name = "milkymist-ac97",
-    .size = sizeof(MilkymistAC97State),
-    .vmsd = &vmstate_milkymist_ac97,
-    .reset = milkymist_ac97_reset,
-    .class_init = milkymist_ac97_class_init,
+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 46e8ae6..b5122af 100644
--- a/hw/milkymist-hpdmc.c
+++ b/hw/milkymist-hpdmc.c
@@ -147,22 +147,24 @@ static const VMStateDescription vmstate_milkymist_hpdmc = {
 
 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 DeviceInfo milkymist_hpdmc_info = {
-    .name = "milkymist-hpdmc",
-    .size = sizeof(MilkymistHpdmcState),
-    .vmsd = &vmstate_milkymist_hpdmc,
-    .reset = milkymist_hpdmc_reset,
-    .class_init = milkymist_hpdmc_class_init,
+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 97eb793..3c1c68a 100644
--- a/hw/milkymist-memcard.c
+++ b/hw/milkymist-memcard.c
@@ -280,22 +280,24 @@ static const VMStateDescription vmstate_milkymist_memcard = {
 
 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 DeviceInfo milkymist_memcard_info = {
-    .name = "milkymist-memcard",
-    .size = sizeof(MilkymistMemcardState),
-    .vmsd = &vmstate_milkymist_memcard,
-    .reset = milkymist_memcard_reset,
-    .class_init = milkymist_memcard_class_init,
+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 1ac6c6a..b9b553f 100644
--- a/hw/milkymist-minimac2.c
+++ b/hw/milkymist-minimac2.c
@@ -526,23 +526,25 @@ static Property milkymist_minimac2_properties[] = {
 
 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 DeviceInfo milkymist_minimac2_info = {
-    .name = "milkymist-minimac2",
-    .size = sizeof(MilkymistMinimac2State),
-    .vmsd = &vmstate_milkymist_minimac2,
-    .reset = milkymist_minimac2_reset,
-    .props = milkymist_minimac2_properties,
-    .class_init = milkymist_minimac2_class_init,
+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 b6ade5a..1b73a46 100644
--- a/hw/milkymist-pfpu.c
+++ b/hw/milkymist-pfpu.c
@@ -521,22 +521,24 @@ static const VMStateDescription vmstate_milkymist_pfpu = {
 
 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 DeviceInfo milkymist_pfpu_info = {
-    .name = "milkymist-pfpu",
-    .size = sizeof(MilkymistPFPUState),
-    .vmsd = &vmstate_milkymist_pfpu,
-    .reset = milkymist_pfpu_reset,
-    .class_init = milkymist_pfpu_class_init,
+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 f4d2dad..5d496cb 100644
--- a/hw/milkymist-softusb.c
+++ b/hw/milkymist-softusb.c
@@ -307,23 +307,25 @@ static Property milkymist_softusb_properties[] = {
 
 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 DeviceInfo milkymist_softusb_info = {
-    .name = "milkymist-softusb",
-    .size = sizeof(MilkymistSoftUsbState),
-    .vmsd = &vmstate_milkymist_softusb,
-    .reset = milkymist_softusb_reset,
-    .props = milkymist_softusb_properties,
-    .class_init = milkymist_softusb_class_init,
+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 4b017fa..18171f6 100644
--- a/hw/milkymist-sysctl.c
+++ b/hw/milkymist-sysctl.c
@@ -306,23 +306,25 @@ static Property milkymist_sysctl_properties[] = {
 
 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 DeviceInfo milkymist_sysctl_info = {
-    .name = "milkymist-sysctl",
-    .size = sizeof(MilkymistSysctlState),
-    .vmsd = &vmstate_milkymist_sysctl,
-    .reset = milkymist_sysctl_reset,
-    .props = milkymist_sysctl_properties,
-    .class_init = milkymist_sysctl_class_init,
+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 4004a12..474eae0 100644
--- a/hw/milkymist-tmu2.c
+++ b/hw/milkymist-tmu2.c
@@ -467,22 +467,24 @@ static const VMStateDescription vmstate_milkymist_tmu2 = {
 
 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 DeviceInfo milkymist_tmu2_info = {
-    .name = "milkymist-tmu2",
-    .size = sizeof(MilkymistTMU2State),
-    .vmsd = &vmstate_milkymist_tmu2,
-    .reset = milkymist_tmu2_reset,
-    .class_init = milkymist_tmu2_class_init,
+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 312976d..2999b79 100644
--- a/hw/milkymist-uart.c
+++ b/hw/milkymist-uart.c
@@ -220,22 +220,24 @@ static const VMStateDescription vmstate_milkymist_uart = {
 
 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 DeviceInfo milkymist_uart_info = {
-    .name = "milkymist-uart",
-    .size = sizeof(MilkymistUartState),
-    .vmsd = &vmstate_milkymist_uart,
-    .reset = milkymist_uart_reset,
-    .class_init = milkymist_uart_class_init,
+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 81d31fa..92ad02f 100644
--- a/hw/milkymist-vgafb.c
+++ b/hw/milkymist-vgafb.c
@@ -307,23 +307,25 @@ static Property milkymist_vgafb_properties[] = {
 
 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 DeviceInfo milkymist_vgafb_info = {
-    .name = "milkymist-vgafb",
-    .size = sizeof(MilkymistVgafbState),
-    .vmsd = &vmstate_milkymist_vgafb,
-    .reset = milkymist_vgafb_reset,
-    .props = milkymist_vgafb_properties,
-    .class_init = milkymist_vgafb_class_init,
+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/mips_malta.c b/hw/mips_malta.c
index 64603ce..d232630 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -1014,13 +1014,11 @@ static void mips_malta_class_init(ObjectClass *klass, void *data)
     k->init = mips_malta_sysbus_device_init;
 }
 
-static DeviceInfo mips_malta_device = {
-    .name  = "mips-malta",
-    .size  = sizeof(MaltaState),
-    .class_init = mips_malta_class_init,
-    .props = (Property[]) {
-        DEFINE_PROP_END_OF_LIST(),
-    }
+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 = {
@@ -1033,7 +1031,7 @@ static QEMUMachine mips_malta_machine = {
 
 static void mips_malta_device_init(void)
 {
-    sysbus_qdev_register(&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 8cf9161..a0e6c9f 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -259,24 +259,26 @@ static Property mipsnet_properties[] = {
 
 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 DeviceInfo mipsnet_info = {
-    .name = "mipsnet",
-    .desc = "MIPS Simulator network device",
-    .size = sizeof(MIPSnetState),
-    .vmsd = &vmstate_mipsnet,
-    .reset = mipsnet_sysbus_reset,
-    .props = mipsnet_properties,
-    .class_init = mipsnet_class_init,
+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 ec6bb4f..28cd60d 100644
--- a/hw/mpc8544_guts.c
+++ b/hw/mpc8544_guts.c
@@ -128,14 +128,15 @@ static void mpc8544_guts_class_init(ObjectClass *klass, void *data)
     k->init = mpc8544_guts_initfn;
 }
 
-static DeviceInfo mpc8544_guts_info = {
-    .name = "mpc8544-guts",
-    .size = sizeof(GutsState),
-    .class_init = mpc8544_guts_class_init,
+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/mst_fpga.c b/hw/mst_fpga.c
index 513bfa6..1729db0 100644
--- a/hw/mst_fpga.c
+++ b/hw/mst_fpga.c
@@ -240,21 +240,23 @@ static VMStateDescription 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 DeviceInfo mst_fpga_info = {
-    .name = "mainstone-fpga",
-    .desc = "Mainstone II FPGA",
-    .size = sizeof(mst_irq_state),
-    .vmsd = &vmstate_mst_fpga_regs,
-    .class_init = mst_fpga_class_init,
+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 a2fc4bb..ac90924 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -419,17 +419,19 @@ static Property mv88w8618_eth_properties[] = {
 
 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 DeviceInfo mv88w8618_eth_info = {
-    .name = "mv88w8618_eth",
-    .size = sizeof(mv88w8618_eth_state),
-    .vmsd = &mv88w8618_eth_vmsd,
-    .props = mv88w8618_eth_properties,
-    .class_init = mv88w8618_eth_class_init,
+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 */
@@ -635,16 +637,18 @@ static const VMStateDescription 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 DeviceInfo musicpal_lcd_info = {
-    .name = "musicpal_lcd",
-    .size = sizeof(musicpal_lcd_state),
-    .vmsd = &musicpal_lcd_vmsd,
-    .class_init = musicpal_lcd_class_init,
+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 */
@@ -751,17 +755,19 @@ static const VMStateDescription 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 DeviceInfo mv88w8618_pic_info = {
-    .name = "mv88w8618_pic",
-    .size = sizeof(mv88w8618_pic_state),
-    .reset = mv88w8618_pic_reset,
-    .vmsd = &mv88w8618_pic_vmsd,
-    .class_init = mv88w8618_pic_class_init,
+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 */
@@ -926,17 +932,19 @@ static const VMStateDescription 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 DeviceInfo mv88w8618_pit_info = {
-    .name = "mv88w8618_pit",
-    .size = sizeof(mv88w8618_pit_state),
-    .reset = mv88w8618_pit_reset,
-    .vmsd = &mv88w8618_pit_vmsd,
-    .class_init = mv88w8618_pit_class_init,
+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 */
@@ -1005,16 +1013,18 @@ static const VMStateDescription 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 DeviceInfo mv88w8618_flashcfg_info = {
-    .name = "mv88w8618_flashcfg",
-    .size = sizeof(mv88w8618_flashcfg_state),
-    .vmsd = &mv88w8618_flashcfg_vmsd,
-    .class_init = mv88w8618_flashcfg_class_init,
+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 */
@@ -1324,17 +1334,19 @@ static const VMStateDescription 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 DeviceInfo musicpal_gpio_info = {
-    .name = "musicpal_gpio",
-    .size = sizeof(musicpal_gpio_state),
-    .reset = musicpal_gpio_reset,
-    .vmsd = &musicpal_gpio_vmsd,
-    .class_init = musicpal_gpio_class_init,
+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 */
@@ -1477,16 +1489,18 @@ static const VMStateDescription 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 DeviceInfo musicpal_key_info = {
-    .name = "musicpal_key",
-    .size = sizeof(musicpal_key_state),
-    .vmsd = &musicpal_key_vmsd,
-    .class_init = musicpal_key_class_init,
+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 = {
@@ -1660,22 +1674,23 @@ static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data)
     sdc->init = mv88w8618_wlan_init;
 }
 
-static DeviceInfo mv88w8618_wlan_info = {
-    .name = "mv88w8618_wlan",
-    .size = sizeof(SysBusDevice),
-    .class_init = mv88w8618_wlan_class_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_qdev_register(&mv88w8618_wlan_info);
-    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 6248731..5d947b1 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -426,23 +426,25 @@ static Property nand_properties[] = {
 
 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 DeviceInfo nand_info = {
-    .name = "nand",
-    .size = sizeof(NANDFlashState),
-    .reset = nand_reset,
-    .vmsd = &vmstate_nand,
-    .props = nand_properties,
-    .class_init = nand_class_init,
+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 25a7a31..1352282 100644
--- a/hw/ne2000-isa.c
+++ b/hw/ne2000-isa.c
@@ -82,27 +82,31 @@ static int isa_ne2000_initfn(ISADevice *dev)
     return 0;
 }
 
+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 DeviceInfo ne2000_isa_info = {
-    .name  = "ne2k_isa",
-    .size  = sizeof(ISANE2000State),
-    .class_init       = isa_ne2000_class_initfn,
-    .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 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 138479a..080811e 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -793,6 +793,7 @@ static Property ne2000_properties[] = {
 
 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;
@@ -800,19 +801,20 @@ static void ne2000_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo ne2000_info = {
-    .name = "ne2k_pci",
-    .size = sizeof(PCINE2000State),
-    .vmsd = &vmstate_pci_ne2000,
-    .props = ne2000_properties,
-    .class_init = ne2000_class_init,
+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 97d2d93..9a9a8e1 100644
--- a/hw/omap_gpio.c
+++ b/hw/omap_gpio.c
@@ -739,17 +739,19 @@ static Property omap_gpio_properties[] = {
 
 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 DeviceInfo omap_gpio_info = {
-    .name = "omap-gpio",
-    .size = sizeof(struct omap_gpif_s),
-    .reset = omap_gpif_reset,
-    .props = omap_gpio_properties,
-    .class_init = omap_gpio_class_init,
+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[] = {
@@ -766,23 +768,25 @@ static Property omap2_gpio_properties[] = {
 
 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 DeviceInfo omap2_gpio_info = {
-    .name = "omap2-gpio",
-    .size = sizeof(struct omap2_gpif_s),
-    .reset = omap2_gpif_reset,
-    .props = omap2_gpio_properties,
-    .class_init = omap2_gpio_class_init,
+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 310fe2d..5aa98a8 100644
--- a/hw/omap_intc.c
+++ b/hw/omap_intc.c
@@ -381,17 +381,19 @@ static Property omap_intc_properties[] = {
 
 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 DeviceInfo omap_intc_info = {
-    .name = "omap-intc",
-    .size = sizeof(struct omap_intr_handler_s),
-    .reset = omap_inth_reset,
-    .props = omap_intc_properties,
-    .class_init = omap_intc_class_init,
+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,
@@ -623,23 +625,25 @@ static Property omap2_intc_properties[] = {
 
 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 DeviceInfo omap2_intc_info = {
-    .name = "omap2-intc",
-    .size = sizeof(struct omap_intr_handler_s),
-    .reset = omap_inth_reset,
-    .props = omap2_intc_properties,
-    .class_init = omap2_intc_class_init,
+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 e20d4d9..8744b04 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -813,22 +813,24 @@ static Property onenand_properties[] = {
 
 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 DeviceInfo onenand_info = {
-    .name = "onenand",
-    .size = sizeof(OneNANDState),
-    .reset = onenand_system_reset,
-    .props = onenand_properties,
-    .class_init = onenand_class_init,
+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 1f45506..09f2757 100644
--- a/hw/opencores_eth.c
+++ b/hw/opencores_eth.c
@@ -734,23 +734,25 @@ static Property open_eth_properties[] = {
 
 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 DeviceInfo open_eth_info = {
-    .name = "open_eth",
-    .desc = "Opencores 10/100 Mbit Ethernet",
-    .size = sizeof(OpenEthState),
-    .reset = qdev_open_eth_reset,
-    .props = open_eth_properties,
-    .class_init = open_eth_class_init,
+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/parallel.c b/hw/parallel.c
index cadcffb..484d727 100644
--- a/hw/parallel.c
+++ b/hw/parallel.c
@@ -583,28 +583,32 @@ bool parallel_mm_init(MemoryRegion *address_space,
     return true;
 }
 
+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 DeviceInfo parallel_isa_info = {
-    .name  = "isa-parallel",
-    .size  = sizeof(ISAParallelState),
-    .class_init       = parallel_isa_class_initfn,
-    .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 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 31608d3..7f3aa65 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -499,22 +499,24 @@ static int port92_initfn(ISADevice *dev)
 
 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 DeviceInfo port92_info = {
-    .name     = "port92",
-    .size     = sizeof(Port92State),
-    .vmsd     = &vmstate_port92_isa,
-    .no_user  = 1,
-    .reset    = port92_reset,
-    .class_init          = port92_class_initfn,
+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)
 
diff --git a/hw/pci.c b/hw/pci.c
index 43dc1fb..8fd450c 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1521,17 +1521,6 @@ static int pci_unplug_device(DeviceState *qdev)
                              PCI_HOTPLUG_DISABLED);
 }
 
-void pci_qdev_register(DeviceInfo *info)
-{
-    info->init = pci_qdev_init;
-    if (!info->unplug) {
-        info->unplug = pci_unplug_device;
-    }
-    info->exit = pci_unregister_device;
-    info->bus_info = &pci_bus_info;
-    qdev_register_subclass(info, TYPE_PCI_DEVICE);
-}
-
 PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
                                     const char *name)
 {
@@ -1995,12 +1984,22 @@ 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)
diff --git a/hw/pci.h b/hw/pci.h
index 09b2324..33b0b18 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -464,8 +464,6 @@ pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask)
     return val & mask;
 }
 
-void pci_qdev_register(DeviceInfo *info);
-
 PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
                                     const char *name);
 PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
diff --git a/hw/pckbd.c b/hw/pckbd.c
index 2ebe1c5..b4c53be 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -499,20 +499,22 @@ static int i8042_initfn(ISADevice *dev)
 
 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 DeviceInfo i8042_info = {
-    .name     = "i8042",
-    .size     = sizeof(ISAKBDState),
-    .vmsd     = &vmstate_kbd_isa,
-    .no_user  = 1,
-    .class_init          = i8042_class_initfn,
+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 be3bd79..439f32c 100644
--- a/hw/pcnet-pci.c
+++ b/hw/pcnet-pci.c
@@ -355,6 +355,7 @@ static Property pcnet_properties[] = {
 
 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;
@@ -363,20 +364,21 @@ static void pcnet_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo pcnet_info = {
-    .name = "pcnet",
-    .size = sizeof(PCIPCNetState),
-    .reset = pci_reset,
-    .vmsd = &vmstate_pci_pcnet,
-    .props = pcnet_properties,
-    .class_init = pcnet_class_init,
+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/piix4.c b/hw/piix4.c
index 88be535..4e7a237 100644
--- a/hw/piix4.c
+++ b/hw/piix4.c
@@ -104,6 +104,7 @@ int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn)
 
 static void piix4_class_init(ObjectClass *klass, void *data)
 {
+    DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
     k->no_hotplug = 1;
@@ -111,19 +112,20 @@ static void piix4_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo piix4_info = {
-    .name = "PIIX4",
-    .desc = "ISA bridge",
-    .size = sizeof(PIIX4State),
-    .vmsd = &vmstate_piix4,
-    .no_user = 1,
-    .class_init = piix4_class_init,
+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(&piix4_info);
+    type_register_static(&piix4_info);
 }
 device_init(piix4_register);
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 8b01782..2bbfa4a 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -504,8 +504,12 @@ static int piix3_initfn(PCIDevice *dev)
 
 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;
@@ -514,19 +518,21 @@ static void piix3_class_init(ObjectClass *klass, void *data)
     k->class_id     = PCI_CLASS_BRIDGE_ISA;
 }
 
-static DeviceInfo piix3_info = {
-    .name    = "PIIX3",
-    .desc    = "ISA bridge",
-    .size    = sizeof(PIIX3State),
-    .vmsd    = &vmstate_piix3,
-    .no_user = 1,
-    .class_init = piix3_class_init,
+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;
@@ -535,17 +541,16 @@ static void piix3_xen_class_init(ObjectClass *klass, void *data)
     k->class_id     = PCI_CLASS_BRIDGE_ISA;
 };
 
-static DeviceInfo piix3_xen_info = {
-    .name    = "PIIX3-xen",
-    .desc    = "ISA bridge",
-    .size    = sizeof(PIIX3State),
-    .vmsd    = &vmstate_piix3,
-    .no_user = 1,
-    .class_init = piix3_xen_class_init,
+static TypeInfo piix3_xen_info = {
+    .name          = "PIIX3-xen",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PIIX3State),
+    .class_init    = piix3_xen_class_init,
 };
 
 static void i440fx_class_init(ObjectClass *klass, void *data)
 {
+    DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
     k->no_hotplug = 1;
@@ -555,37 +560,40 @@ static void i440fx_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo i440fx_info = {
-    .name = "i440FX",
-    .desc = "Host bridge",
-    .size = sizeof(PCII440FXState),
-    .vmsd = &vmstate_i440fx,
-    .no_user = 1,
-    .class_init = i440fx_class_init,
+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 DeviceInfo i440fx_pcihost_info = {
-    .name = "i440FX-pcihost",
-    .fw_name = "pci",
-    .size = sizeof(I440FXState),
-    .no_user = 1,
-    .class_init = i440fx_pcihost_class_init,
+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)
 {
-    pci_qdev_register(&i440fx_info);
-    pci_qdev_register(&piix3_info);
-    pci_qdev_register(&piix3_xen_info);
-    sysbus_register_withprop(&i440fx_pcihost_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 088aa44..8db2248 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -295,10 +295,11 @@ static void pl011_arm_class_init(ObjectClass *klass, void *data)
     sdc->init = pl011_arm_init;
 }
 
-static DeviceInfo pl011_arm_info = {
-    .name = "pl011",
-    .size = sizeof(pl011_state),
-    .class_init = pl011_arm_class_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)
@@ -308,16 +309,17 @@ static void pl011_luminary_class_init(ObjectClass *klass, void *data)
     sdc->init = pl011_luminary_init;
 }
 
-static DeviceInfo pl011_luminary_info = {
-    .name = "pl011_luminary",
-    .size = sizeof(pl011_state),
-    .class_init = pl011_luminary_class_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_qdev_register(&pl011_arm_info);
-    sysbus_qdev_register(&pl011_luminary_info);
+    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 4f62712..30bd344 100644
--- a/hw/pl022.c
+++ b/hw/pl022.c
@@ -292,15 +292,16 @@ static void pl022_class_init(ObjectClass *klass, void *data)
     sdc->init = pl022_init;
 }
 
-static DeviceInfo pl022_info = {
-    .name = "pl022",
-    .size = sizeof(pl022_state),
-    .class_init = pl022_class_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_qdev_register(&pl022_info);
+    type_register_static(&pl022_info);
 }
 
 device_init(pl022_register_devices)
diff --git a/hw/pl031.c b/hw/pl031.c
index 4cb8528..8416a60 100644
--- a/hw/pl031.c
+++ b/hw/pl031.c
@@ -215,22 +215,24 @@ static int pl031_init(SysBusDevice *dev)
 
 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 DeviceInfo pl031_info = {
-    .name = "pl031",
-    .size = sizeof(pl031_state),
-    .vmsd = &vmstate_pl031,
-    .no_user = 1,
-    .class_init = pl031_class_init,
+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 0482851..6d99c9c 100644
--- a/hw/pl041.c
+++ b/hw/pl041.c
@@ -621,24 +621,26 @@ static Property pl041_device_properties[] = {
 
 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 DeviceInfo pl041_device_info = {
-    .name = "pl041",
-    .size = sizeof(pl041_state),
-    .vmsd = &vmstate_pl041,
-    .reset = pl041_device_reset,
-    .no_user = 1,
-    .props = pl041_device_properties,
-    .class_init = pl041_device_class_init,
+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 5f60508..b0094ac 100644
--- a/hw/pl050.c
+++ b/hw/pl050.c
@@ -159,36 +159,40 @@ static int pl050_init_mouse(SysBusDevice *dev)
 
 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 DeviceInfo pl050_kbd_info = {
-    .name = "pl050_keyboard",
-    .size = sizeof(pl050_state),
-    .vmsd = &vmstate_pl050,
-    .class_init = pl050_kbd_class_init,
+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 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 DeviceInfo pl050_mouse_info = {
-    .name = "pl050_mouse",
-    .size = sizeof(pl050_state),
-    .vmsd = &vmstate_pl050,
-    .class_init = pl050_mouse_class_init,
+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 9dc9406..3136c99 100644
--- a/hw/pl061.c
+++ b/hw/pl061.c
@@ -295,36 +295,40 @@ static int pl061_init_arm(SysBusDevice *dev)
 
 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 DeviceInfo pl061_info = {
-    .name = "pl061",
-    .size = sizeof(pl061_state),
-    .vmsd = &vmstate_pl061,
-    .class_init = pl061_class_init,
+static TypeInfo pl061_info = {
+    .name          = "pl061",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl061_state),
+    .class_init    = pl061_class_init,
 };
 
 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 DeviceInfo pl061_luminary_info = {
-    .name = "pl061_luminary",
-    .size = sizeof(pl061_state),
-    .vmsd = &vmstate_pl061,
-    .class_init = pl061_luminary_class_init,
+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 727bfa1..4405d18 100644
--- a/hw/pl080.c
+++ b/hw/pl080.c
@@ -375,40 +375,44 @@ static int pl081_init(SysBusDevice *dev)
 
 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 DeviceInfo pl080_info = {
-    .name = "pl080",
-    .size = sizeof(pl080_state),
-    .vmsd = &vmstate_pl080,
-    .no_user = 1,
-    .class_init = pl080_class_init,
+static TypeInfo pl080_info = {
+    .name          = "pl080",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl080_state),
+    .class_init    = pl080_class_init,
 };
 
 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 DeviceInfo pl081_info = {
-    .name = "pl081",
-    .size = sizeof(pl080_state),
-    .vmsd = &vmstate_pl080,
-    .no_user = 1,
-    .class_init = pl081_class_init,
+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 58fb9d3..86e95a3 100644
--- a/hw/pl110.c
+++ b/hw/pl110.c
@@ -471,54 +471,60 @@ static int pl111_init(SysBusDevice *dev)
 
 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 DeviceInfo pl110_info = {
-    .name = "pl110",
-    .size = sizeof(pl110_state),
-    .vmsd = &vmstate_pl110,
-    .no_user = 1,
-    .class_init = pl110_class_init,
+static TypeInfo pl110_info = {
+    .name          = "pl110",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl110_state),
+    .class_init    = pl110_class_init,
 };
 
 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 DeviceInfo pl110_versatile_info = {
-    .name = "pl110_versatile",
-    .size = sizeof(pl110_state),
-    .vmsd = &vmstate_pl110,
-    .no_user = 1,
-    .class_init = pl110_versatile_class_init,
+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 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 DeviceInfo pl111_info = {
-    .name = "pl111",
-    .size = sizeof(pl110_state),
-    .vmsd = &vmstate_pl110,
-    .no_user = 1,
-    .class_init = pl111_class_init,
+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 973d3fc..ae636e2 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -490,22 +490,24 @@ static int pl181_init(SysBusDevice *dev)
 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 DeviceInfo pl181_info = {
-    .name = "pl181",
-    .size = sizeof(pl181_state),
-    .class_init = pl181_class_init,
-    .vmsd = &vmstate_pl181,
-    .reset = pl181_reset,
-    .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_qdev_register(&pl181_info);
+    type_register_static(&pl181_info);
 }
 
 device_init(pl181_register_devices)
diff --git a/hw/pl190.c b/hw/pl190.c
index 79322aa..956ab21 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -257,23 +257,25 @@ static const VMStateDescription vmstate_pl190 = {
 
 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 DeviceInfo pl190_info = {
-    .name = "pl190",
-    .size = sizeof(pl190_state),
-    .vmsd = &vmstate_pl190,
-    .reset = pl190_reset,
-    .no_user = 1,
-    .class_init = pl190_class_init,
+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/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index 36fb9f9..d11f120 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -369,36 +369,40 @@ static int ppc4xx_pcihost_initfn(SysBusDevice *dev)
 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 DeviceInfo ppc4xx_host_bridge_info = {
-    .name    = "ppc4xx-host-bridge",
-    .desc    = "Host bridge",
-    .size    = sizeof(PCIDevice),
-    .class_init = ppc4xx_host_bridge_class_init,
+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 DeviceInfo ppc4xx_pcihost_info = {
-    .name    = "ppc4xx-pcihost",
-    .size    = sizeof(PPC4xxPCIState),
-    .vmsd    = &vmstate_ppc4xx_pci,
-    .class_init = ppc4xx_pcihost_class_init,
+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)
 {
-    sysbus_register_withprop(&ppc4xx_pcihost_info);
-    pci_qdev_register(&ppc4xx_host_bridge_info);
+    type_register_static(&ppc4xx_pcihost_info);
+    type_register_static(&ppc4xx_host_bridge_info);
 }
 device_init(ppc4xx_pci_register);
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 438a75d..ff9594e 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -610,7 +610,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
     pcihost = DO_UPCAST(PCIHostState, busdev, sys);
     pcihost->address_space = get_system_memory();
     qdev_init_nofail(dev);
-    qdev_property_add_child(qdev_get_root(), "raven", dev, NULL);
+    qdev_property_add_child(qdev_get_root(), "raven", DEVICE(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");
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index f8c4f11..d5bce71 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -341,37 +341,41 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
 
 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 DeviceInfo e500_host_bridge_info = {
-    .name = "e500-host-bridge",
-    .desc = "Host bridge",
-    .size = sizeof(PCIDevice),
-    .class_init = e500_host_bridge_class_init,
+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 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 DeviceInfo e500_pcihost_info = {
-    .name = "e500-pcihost",
-    .size = sizeof(PPCE500PCIState),
-    .vmsd = &vmstate_ppce500_pci,
-    .class_init = e500_pcihost_class_init,
+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 cb5bc97..9d648ec 100644
--- a/hw/ppce500_spin.c
+++ b/hw/ppce500_spin.c
@@ -210,14 +210,15 @@ static void ppce500_spin_class_init(ObjectClass *klass, void *data)
     k->init = ppce500_spin_initfn;
 }
 
-static DeviceInfo ppce500_spin_info = {
-    .name = "e500-spin",
-    .size = sizeof(SpinState),
-    .class_init = ppce500_spin_class_init,
+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 b3b85b7..40b8bb0 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -137,42 +137,46 @@ static const VMStateDescription vmstate_raven = {
 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 DeviceInfo raven_info = {
+static TypeInfo raven_info = {
     .name = "raven",
-    .desc = "PReP Host Bridge - Motorola Raven",
-    .size = sizeof(RavenPCIState),
-    .vmsd = &vmstate_raven,
-    .no_user = 1,
+    .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 DeviceInfo raven_pcihost_info = {
+static TypeInfo raven_pcihost_info = {
     .name = "raven-pcihost",
-    .fw_name = "pci",
-    .size = sizeof(PREPPCIState),
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PREPPCIState),
     .class_init = raven_pcihost_class_init,
-    .no_user = 1,
 };
 
 static void raven_register_devices(void)
 {
-    sysbus_register_withprop(&raven_pcihost_info);
-    pci_qdev_register(&raven_info);
+    type_register_static(&raven_pcihost_info);
+    type_register_static(&raven_info);
 }
 
 device_init(raven_register_devices)
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index fbc397f..244c614 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -1235,17 +1235,19 @@ static const VMStateDescription 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 DeviceInfo pxa2xx_rtc_sysbus_info = {
-    .name = "pxa2xx_rtc",
-    .desc = "PXA2xx RTC Controller",
-    .size = sizeof(PXA2xxRTCState),
-    .vmsd = &vmstate_pxa2xx_rtc_regs,
-    .class_init = pxa2xx_rtc_sysbus_class_init,
+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 */
@@ -1489,10 +1491,11 @@ static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data)
     k->send = pxa2xx_i2c_tx;
 }
 
-static DeviceInfo pxa2xx_i2c_slave_info = {
-    .name = "pxa2xx-i2c-slave",
-    .size = sizeof(PXA2xxI2CSlaveState),
-    .class_init = pxa2xx_i2c_slave_class_init,
+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,
@@ -1548,18 +1551,20 @@ static Property pxa2xx_i2c_properties[] = {
 
 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 DeviceInfo pxa2xx_i2c_info = {
-    .name = "pxa2xx_i2c",
-    .desc = "PXA2xx I2C Bus Controller",
-    .size = sizeof(PXA2xxI2CState),
-    .vmsd = &vmstate_pxa2xx_i2c,
-    .props = pxa2xx_i2c_properties,
-    .class_init = pxa2xx_i2c_class_init,
+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 */
@@ -2318,18 +2323,19 @@ static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data)
     sdc->init = pxa2xx_ssp_init;
 }
 
-static DeviceInfo pxa2xx_ssp_info = {
-    .name = "pxa2xx-ssp",
-    .size = sizeof(PXA2xxSSPState),
-    .class_init = pxa2xx_ssp_class_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_qdev_register(&pxa2xx_ssp_info);
-    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 9ecec33..2d61565 100644
--- a/hw/pxa2xx_dma.c
+++ b/hw/pxa2xx_dma.c
@@ -550,22 +550,24 @@ static Property pxa2xx_dma_properties[] = {
 
 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 DeviceInfo pxa2xx_dma_info = {
-    .name = "pxa2xx-dma",
-    .desc = "PXA2xx DMA controller",
-    .size = sizeof(PXA2xxDMAState),
-    .vmsd = &vmstate_pxa2xx_dma,
-    .props = pxa2xx_dma_properties,
-    .class_init = pxa2xx_dma_class_init,
+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 7a1333f..67fd17c 100644
--- a/hw/pxa2xx_gpio.c
+++ b/hw/pxa2xx_gpio.c
@@ -325,21 +325,23 @@ static Property pxa2xx_gpio_properties[] = {
 
 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 DeviceInfo pxa2xx_gpio_info = {
-    .name = "pxa2xx-gpio",
-    .desc = "PXA2xx GPIO controller",
-    .size = sizeof(PXA2xxGPIOInfo),
-    .props = pxa2xx_gpio_properties,
-    .class_init = pxa2xx_gpio_class_init,
+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 d318e83..ca85743 100644
--- a/hw/pxa2xx_pic.c
+++ b/hw/pxa2xx_pic.c
@@ -298,21 +298,23 @@ static int pxa2xx_pic_initfn(SysBusDevice *dev)
 
 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 DeviceInfo pxa2xx_pic_info = {
-    .name = "pxa2xx_pic",
-    .desc = "PXA2xx PIC",
-    .size = sizeof(PXA2xxPICState),
-    .vmsd = &vmstate_pxa2xx_pic_regs,
-    .class_init = pxa2xx_pic_class_init,
+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 cd78d41..9080075 100644
--- a/hw/pxa2xx_timer.c
+++ b/hw/pxa2xx_timer.c
@@ -486,18 +486,20 @@ static Property pxa25x_timer_dev_properties[] = {
 
 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 DeviceInfo pxa25x_timer_dev_info = {
-    .name = "pxa25x-timer",
-    .desc = "PXA25x timer",
-    .size = sizeof(PXA2xxTimerInfo),
-    .vmsd = &vmstate_pxa2xx_timer_regs,
-    .props = pxa25x_timer_dev_properties,
-    .class_init = pxa25x_timer_dev_class_init,
+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[] = {
@@ -509,23 +511,25 @@ static Property pxa27x_timer_dev_properties[] = {
 
 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 DeviceInfo pxa27x_timer_dev_info = {
-    .name = "pxa27x-timer",
-    .desc = "PXA27x timer",
-    .size = sizeof(PXA2xxTimerInfo),
-    .vmsd = &vmstate_pxa2xx_timer_regs,
-    .props = pxa27x_timer_dev_properties,
-    .class_init = pxa27x_timer_dev_class_init,
+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.h b/hw/qdev.h
index af167be..ce76625 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -260,7 +260,6 @@ struct DeviceInfo {
     BusInfo *bus_info;
 };
 
-void qdev_register(DeviceInfo *info);
 void qdev_register_subclass(DeviceInfo *info, const char *parent);
 
 /* Register device properties.  */
diff --git a/hw/qxl.c b/hw/qxl.c
index 2f9470f..bc03c1d 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1826,6 +1826,7 @@ static Property 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;
@@ -1834,42 +1835,45 @@ static void qxl_primary_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo qxl_primary_info = {
-    .name = "qxl-vga",
-    .desc = "Spice QXL GPU (primary, vga compatible)",
-    .size = sizeof(PCIQXLDevice),
-    .reset = qxl_reset_handler,
-    .vmsd = &qxl_vmstate,
-    .props = qxl_properties,
-    .class_init = qxl_primary_class_init,
+static TypeInfo qxl_primary_info = {
+    .name          = "qxl-vga",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIQXLDevice),
+    .class_init    = qxl_primary_class_init,
 };
 
 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 DeviceInfo qxl_secondary_info = {
-    .name = "qxl",
-    .desc = "Spice QXL GPU (secondary)",
-    .size = sizeof(PCIQXLDevice),
-    .reset = qxl_reset_handler,
-    .vmsd = &qxl_vmstate,
-    .props = qxl_properties,
-    .class_init = qxl_secondary_class_init,
+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_primary_info);
-    pci_qdev_register(&qxl_secondary_info);
+    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 42a0f20..821e627 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -89,15 +89,16 @@ static void realview_i2c_class_init(ObjectClass *klass, void *data)
     k->init = realview_i2c_init;
 }
 
-static DeviceInfo realview_i2c_info = {
-    .name = "realview_i2c",
-    .size = sizeof(RealViewI2CState),
-    .class_init = realview_i2c_class_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.  */
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index 0ccf21a..4121502 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -53,15 +53,16 @@ static void realview_gic_class_init(ObjectClass *klass, void *data)
     sdc->init = realview_gic_init;
 }
 
-static DeviceInfo realview_gic_info = {
-    .name = "realview_gic",
-    .size = sizeof(RealViewGICState),
-    .class_init = realview_gic_class_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_qdev_register(&realview_gic_info);
+    type_register_static(&realview_gic_info);
 }
 
 device_init(realview_gic_register_devices)
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 15dec9b..1668390 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -3501,6 +3501,7 @@ static Property rtl8139_properties[] = {
 
 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;
@@ -3510,20 +3511,21 @@ static void rtl8139_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo rtl8139_info = {
-    .name = "rtl8139",
-    .size = sizeof(RTL8139State),
-    .reset = rtl8139_reset,
-    .vmsd = &vmstate_rtl8139,
-    .props = rtl8139_properties,
-    .class_init = rtl8139_class_init,
+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 565941a..a0c610a 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -50,20 +50,6 @@ struct BusInfo s390_virtio_bus_info = {
     .size       = sizeof(VirtIOS390Bus),
 };
 
-typedef struct VirtIOS390DeviceClass
-{
-    DeviceClass parent_class;
-    int (*init)(VirtIOS390Device *dev);
-} VirtIOS390DeviceClass;
-
-#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)
-
 static const VirtIOBindings virtio_s390_bindings;
 
 static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev);
@@ -351,65 +337,77 @@ static const VirtIOBindings virtio_s390_bindings = {
     .get_features = virtio_s390_get_features,
 };
 
+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)
 {
-    VirtIOS390DeviceClass *dc = VIRTIO_S390_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
 
-    dc->init = s390_virtio_net_init;
+    k->init = s390_virtio_net_init;
+    dc->props = s390_virtio_net_properties;
+    dc->alias = "virtio-net";
 }
 
-static DeviceInfo s390_virtio_net = {
-    .name = "virtio-net-s390",
-    .alias = "virtio-net",
-    .size = sizeof(VirtIOS390Device),
-    .class_init = s390_virtio_net_class_init,
-    .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 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)
 {
-    VirtIOS390DeviceClass *dc = VIRTIO_S390_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
 
-    dc->init = s390_virtio_blk_init;
+    k->init = s390_virtio_blk_init;
+    dc->props = s390_virtio_blk_properties;
+    dc->alias = "virtio-blk";
 }
 
-static DeviceInfo s390_virtio_blk = {
-    .name = "virtio-blk-s390",
-    .alias = "virtio-blk",
-    .size = sizeof(VirtIOS390Device),
-    .class_init = s390_virtio_blk_class_init,
-    .props = (Property[]) {
-        DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block),
-        DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+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 Property s390_virtio_serial_properties[] = {
+    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)
 {
-    VirtIOS390DeviceClass *dc = VIRTIO_S390_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
 
-    dc->init = s390_virtio_serial_init;
+    k->init = s390_virtio_serial_init;
+    dc->props = s390_virtio_serial_properties;
+    dc->alias = "virtio-serial";
 }
 
-static DeviceInfo s390_virtio_serial = {
-    .name = "virtio-serial-s390",
-    .alias = "virtio-serial",
-    .size = sizeof(VirtIOS390Device),
-    .class_init = s390_virtio_serial_class_init,
-    .props = (Property[]) {
-        DEFINE_PROP_UINT32("max_ports", VirtIOS390Device,
-                           serial.max_virtserial_ports, 31),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+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)
@@ -420,29 +418,29 @@ static int s390_virtio_busdev_init(DeviceState *dev, DeviceInfo *info)
     return _info->init(_dev);
 }
 
-static void s390_virtio_bus_register_withprop(DeviceInfo *info)
+static void virtio_s390_device_class_init(ObjectClass *klass, void *data)
 {
-    info->init = s390_virtio_busdev_init;
-    info->bus_info = &s390_virtio_bus_info;
-    info->unplug = qdev_simple_unplug_cb;
+    DeviceClass *dc = DEVICE_CLASS(klass);
 
-    assert(info->size >= sizeof(VirtIOS390Device));
-    qdev_register_subclass(info, TYPE_VIRTIO_S390_DEVICE);
+    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,
     .abstract = true,
 };
 
 static void s390_virtio_register(void)
 {
     type_register_static(&virtio_s390_device_info);
-    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(&s390_virtio_serial);
+    type_register_static(&s390_virtio_blk);
+    type_register_static(&s390_virtio_net);
 }
 device_init(s390_virtio_register);
 
@@ -458,21 +456,23 @@ static int s390_virtio_bridge_init(SysBusDevice *dev)
 
 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 DeviceInfo s390_virtio_bridge_info = {
-    .name = "s390-virtio-bridge",
-    .size = sizeof(SysBusDevice),
-    .no_user = 1,
-    .class_init = s390_virtio_bridge_class_init,
+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 d02a907..b5e59b7 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/sb16.c b/hw/sb16.c
index 67357ce..ae25450 100644
--- a/hw/sb16.c
+++ b/hw/sb16.c
@@ -1391,30 +1391,34 @@ int SB16_init (ISABus *bus)
     return 0;
 }
 
+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 DeviceInfo sb16_info = {
-    .name     = "sb16",
-    .desc     = "Creative Sound Blaster 16",
-    .size     = sizeof (SB16State),
-    .vmsd     = &vmstate_sb16,
-    .class_init          = sb16_class_initfn,
-    .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 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 0a062fc..847a4dd 100644
--- a/hw/sbi.c
+++ b/hw/sbi.c
@@ -133,22 +133,24 @@ static int sbi_init1(SysBusDevice *dev)
 
 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 DeviceInfo sbi_info = {
-    .name = "sbi",
-    .size = sizeof(SBIState),
-    .vmsd = &vmstate_sbi,
-    .reset = sbi_reset,
-    .class_init = sbi_class_init,
+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 d017ece..b75044f 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -183,15 +183,6 @@ static int scsi_qdev_exit(DeviceState *qdev)
     return 0;
 }
 
-void scsi_qdev_register(DeviceInfo *info)
-{
-    info->bus_info = &scsi_bus_info;
-    info->init     = scsi_qdev_init;
-    info->unplug   = qdev_simple_unplug_cb;
-    info->exit     = scsi_qdev_exit;
-    qdev_register_subclass(info, TYPE_SCSI_DEVICE);
-}
-
 /* handle legacy '-drive if=scsi,...' cmd line args */
 SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
                                       int unit, bool removable, int bootindex)
@@ -1422,12 +1413,22 @@ 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)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 2be6b67..399e51e 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1712,108 +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 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 DeviceInfo scsi_hd_info = {
-    .name    = "scsi-hd",
-    .fw_name = "disk",
-    .desc    = "virtual SCSI disk",
-    .size    = sizeof(SCSIDiskState),
-    .reset   = scsi_disk_reset,
-    .class_init = scsi_hd_class_initfn,
-    .props   = (Property[]) {
-        DEFINE_SCSI_DISK_PROPERTIES(),
-        DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+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 DeviceInfo scsi_cd_info = {
-    .name    = "scsi-cd",
-    .fw_name = "disk",
-    .desc    = "virtual SCSI CD-ROM",
-    .size    = sizeof(SCSIDiskState),
-    .reset   = scsi_disk_reset,
-    .class_init = scsi_cd_class_initfn,
-    .props   = (Property[]) {
-        DEFINE_SCSI_DISK_PROPERTIES(),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static TypeInfo scsi_cd_info = {
+    .name          = "scsi-cd",
+    .parent        = TYPE_SCSI_DEVICE,
+    .instance_size = sizeof(SCSIDiskState),
+    .class_init    = scsi_cd_class_initfn,
 };
 
 #ifdef __linux__
+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 DeviceInfo scsi_block_info = {
-    .name    = "scsi-block",
-    .fw_name = "disk",
-    .desc    = "SCSI block device passthrough",
-    .size    = sizeof(SCSIDiskState),
-    .reset   = scsi_disk_reset,
-    .class_init = scsi_block_class_initfn,
-    .props   = (Property[]) {
-        DEFINE_SCSI_DISK_PROPERTIES(),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static TypeInfo scsi_block_info = {
+    .name          = "scsi-block",
+    .parent        = TYPE_SCSI_DEVICE,
+    .instance_size = sizeof(SCSIDiskState),
+    .class_init    = scsi_block_class_initfn,
 };
 #endif
 
+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_class_initfn(ObjectClass *klass, void *data)
 {
+    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;
 }
 
-static DeviceInfo scsi_disk_info = {
-    .name    = "scsi-disk", /* legacy -device scsi-disk */
-    .fw_name = "disk",
-    .desc    = "virtual SCSI disk or CD-ROM (legacy)",
-    .size    = sizeof(SCSIDiskState),
-    .reset   = scsi_disk_reset,
-    .class_init = scsi_disk_class_initfn,
-    .props   = (Property[]) {
-        DEFINE_SCSI_DISK_PROPERTIES(),
-        DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+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)
 {
-    scsi_qdev_register(&scsi_hd_info);
-    scsi_qdev_register(&scsi_cd_info);
+    type_register_static(&scsi_hd_info);
+    type_register_static(&scsi_cd_info);
 #ifdef __linux__
-    scsi_qdev_register(&scsi_block_info);
+    type_register_static(&scsi_block_info);
 #endif
-    scsi_qdev_register(&scsi_disk_info);
+    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 5cf4005..4859212 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -457,31 +457,35 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
     return req;
 }
 
+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 DeviceInfo scsi_generic_info = {
-    .name    = "scsi-generic",
-    .fw_name = "disk",
-    .desc    = "pass through generic scsi device (/dev/sg*)",
-    .size    = sizeof(SCSIDevice),
-    .reset   = scsi_generic_reset,
-    .class_init = scsi_generic_class_initfn,
-    .props   = (Property[]) {
-        DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+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 4290b20..dc72b6f 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -125,7 +125,6 @@ struct SCSIBus {
 };
 
 void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info);
-void scsi_qdev_register(DeviceInfo *info);
 
 static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
 {
diff --git a/hw/serial.c b/hw/serial.c
index 2644b13..82917e2 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -879,29 +879,33 @@ SerialState *serial_mm_init(MemoryRegion *address_space,
     return s;
 }
 
+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 DeviceInfo serial_isa_info = {
-    .name  = "isa-serial",
-    .size  = sizeof(ISASerialState),
-    .vmsd  = &vmstate_isa_serial,
-    .class_init       = serial_isa_class_initfn,
-    .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 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 d612cb6..b08e3c5 100644
--- a/hw/sga.c
+++ b/hw/sga.c
@@ -42,20 +42,22 @@ static int sga_initfn(ISADevice *dev)
 }
 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 DeviceInfo sga_info = {
-    .name    = "sga",
-    .desc    = "Serial Graphics Adapter",
-    .size    = sizeof(ISASGAState),
-    .class_init         = sga_class_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 a849176..4234d93 100644
--- a/hw/sh_pci.c
+++ b/hw/sh_pci.c
@@ -156,10 +156,11 @@ static void sh_pci_host_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_HITACHI_SH7751R;
 }
 
-static DeviceInfo sh_pci_host_info = {
-    .name = "sh_pci_host",
-    .size = sizeof(PCIDevice),
-    .class_init = sh_pci_host_class_init,
+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)
@@ -169,16 +170,17 @@ static void sh_pci_device_class_init(ObjectClass *klass, void *data)
     sdc->init = sh_pci_device_init;
 }
 
-static DeviceInfo sh_pci_device_info = {
-    .name = "sh_pci",
-    .size = sizeof(SHPCIState),
-    .class_init = sh_pci_device_class_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_qdev_register(&sh_pci_device_info);
-    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 12ce342..e3701c7 100644
--- a/hw/slavio_intctl.c
+++ b/hw/slavio_intctl.c
@@ -448,22 +448,24 @@ static int slavio_intctl_init1(SysBusDevice *dev)
 
 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 DeviceInfo slavio_intctl_info = {
-    .name = "slavio_intctl",
-    .size = sizeof(SLAVIO_INTCTLState),
-    .vmsd = &vmstate_intctl,
-    .reset = slavio_intctl_reset,
-    .class_init = slavio_intctl_class_init,
+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 39a5269..5a02518 100644
--- a/hw/slavio_misc.c
+++ b/hw/slavio_misc.c
@@ -470,17 +470,19 @@ static int slavio_misc_init1(SysBusDevice *dev)
 
 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 DeviceInfo slavio_misc_info = {
-    .name = "slavio_misc",
-    .size = sizeof(MiscState),
-    .vmsd = &vmstate_misc,
-    .reset = slavio_misc_reset,
-    .class_init = slavio_misc_class_init,
+static TypeInfo slavio_misc_info = {
+    .name          = "slavio_misc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MiscState),
+    .class_init    = slavio_misc_class_init,
 };
 
 static void apc_class_init(ObjectClass *klass, void *data)
@@ -490,16 +492,17 @@ static void apc_class_init(ObjectClass *klass, void *data)
     k->init = apc_init1;
 }
 
-static DeviceInfo apc_info = {
-    .name = "apc",
-    .size = sizeof(MiscState),
-    .class_init = apc_class_init,
+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 a3bebcd..3878f6f 100644
--- a/hw/slavio_timer.c
+++ b/hw/slavio_timer.c
@@ -411,23 +411,25 @@ static Property slavio_timer_properties[] = {
 
 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 DeviceInfo slavio_timer_info = {
-    .name = "slavio_timer",
-    .size = sizeof(SLAVIO_TIMERState),
-    .vmsd = &vmstate_slavio_timer,
-    .reset = slavio_timer_reset,
-    .props = slavio_timer_properties,
-    .class_init = slavio_timer_class_init,
+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/smbus.c b/hw/smbus.c
index ed31a59..77626f3 100644
--- a/hw/smbus.c
+++ b/hw/smbus.c
@@ -207,12 +207,6 @@ static int smbus_device_init(I2CSlave *i2c)
     return sc->init(dev);
 }
 
-void smbus_register_device(DeviceInfo *info)
-{
-    assert(info->size >= sizeof(SMBusDevice));
-    i2c_register_slave_subclass(info, TYPE_SMBUS_DEVICE);
-}
-
 /* Master device commands.  */
 void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read)
 {
diff --git a/hw/smbus.h b/hw/smbus.h
index 90fadee..6ed45bd 100644
--- a/hw/smbus.h
+++ b/hw/smbus.h
@@ -65,8 +65,6 @@ struct SMBusDevice {
     uint8_t command;
 };
 
-void smbus_register_device(DeviceInfo *info);
-
 /* Master device commands.  */
 void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read);
 uint8_t smbus_receive_byte(i2c_bus *bus, uint8_t addr);
diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c
index 401dff5..9d96cbe 100644
--- a/hw/smbus_eeprom.c
+++ b/hw/smbus_eeprom.c
@@ -104,8 +104,14 @@ static int smbus_eeprom_initfn(SMBusDevice *dev)
     return 0;
 }
 
+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;
@@ -114,21 +120,19 @@ static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
     sc->receive_byte = eeprom_receive_byte;
     sc->write_data = eeprom_write_data;
     sc->read_data = eeprom_read_data;
+    dc->props = smbus_eeprom_properties;
 }
 
-static DeviceInfo smbus_eeprom_info = {
-    .name = "smbus-eeprom",
-    .size = sizeof(SMBusEEPROMDevice),
-    .class_init = smbus_eeprom_class_initfn,
-    .props = (Property[]) {
-        DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+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 4220880..1bf2901 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -765,23 +765,25 @@ static Property smc91c111_properties[] = {
 
 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 DeviceInfo smc91c111_info = {
-    .name = "smc91c111",
-    .size = sizeof(smc91c111_state),
-    .vmsd = &vmstate_smc91c111,
-    .reset = smc91c111_reset,
-    .props = smc91c111_properties,
-    .class_init = smc91c111_class_init,
+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_llan.c b/hw/spapr_llan.c
index 0fb176a..79b3941 100644
--- a/hw/spapr_llan.c
+++ b/hw/spapr_llan.c
@@ -482,6 +482,7 @@ static Property spapr_vlan_properties[] = {
 
 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;
@@ -490,13 +491,14 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data)
     k->dt_type = "network";
     k->dt_compatible = "IBM,l-lan";
     k->signal_mask = 0x1;
+    dc->props = spapr_vlan_properties;
 }
 
-static DeviceInfo spapr_vlan_info = {
-    .name = "spapr-vlan",
-    .size = sizeof(VIOsPAPRVLANDevice),
-    .props = spapr_vlan_properties,
-    .class_init = spapr_vlan_class_init,
+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)
@@ -507,6 +509,6 @@ static void spapr_vlan_register(void)
     spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
                              h_add_logical_lan_buffer);
     spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
-    spapr_vio_bus_register_withprop(&spapr_vlan_info);
+    type_register_static(&spapr_vlan_info);
 }
 device_init(spapr_vlan_register);
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index 2a82eae..ed2e4b3 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -221,10 +221,11 @@ static void spapr_main_pci_host_class_init(ObjectClass *klass, void *data)
     k->init = spapr_main_pci_host_init;
 }
 
-static DeviceInfo spapr_main_pci_host_info = {
-    .name = "spapr-pci-host-bridge-pci",
-    .size = sizeof(PCIDevice),
-    .class_init = spapr_main_pci_host_class_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)
@@ -234,16 +235,17 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
     sdc->init = spapr_phb_init;
 }
 
-static DeviceInfo spapr_phb_info = {
-    .name = "spapr-pci-host-bridge",
-    .size = sizeof(sPAPRPHBState),
-    .class_init = spapr_phb_class_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_qdev_register(&spapr_phb_info);
-    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)
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index dc2e9c9..d39a47b 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -680,15 +680,6 @@ static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
     return pc->init(dev);
 }
 
-void spapr_vio_bus_register_withprop(DeviceInfo *info)
-{
-    info->init = spapr_vio_busdev_init;
-    info->bus_info = &spapr_vio_bus_info;
-
-    assert(info->size >= sizeof(VIOsPAPRDevice));
-    qdev_register_subclass(info, TYPE_VIO_SPAPR_DEVICE);
-}
-
 static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr,
                                  target_ulong opcode,
                                  target_ulong *args)
@@ -757,29 +748,39 @@ static int spapr_vio_bridge_init(SysBusDevice *dev)
 
 static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data)
 {
-    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    sbc->init = spapr_vio_bridge_init;
+    k->init = spapr_vio_bridge_init;
+    dc->no_user = 1;
 }
 
-static DeviceInfo spapr_vio_bridge_info = {
-    .name  = "spapr-vio-bridge",
-    .size  = sizeof(SysBusDevice),
-    .no_user = 1,
-    .class_init = spapr_vio_bridge_class_init,
+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);
 }
 
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index 7d1155a..d8527be 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -97,7 +97,6 @@ struct VIOsPAPRBus {
 
 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(DeviceInfo *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 b83bb7f..9cfce19 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -954,6 +954,7 @@ static Property spapr_vscsi_properties[] = {
 
 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;
@@ -962,17 +963,18 @@ static void spapr_vscsi_class_init(ObjectClass *klass, void *data)
     k->dt_type = "vscsi";
     k->dt_compatible = "IBM,v-scsi";
     k->signal_mask = 0x00000001;
+    dc->props = spapr_vscsi_properties;
 }
 
-static DeviceInfo spapr_vscsi_info = {
-    .name = "spapr-vscsi",
-    .size = sizeof(VSCSIState),
-    .props = spapr_vscsi_properties,
-    .class_init = spapr_vscsi_class_init,
+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_info);
+    type_register_static(&spapr_vscsi_info);
 }
 device_init(spapr_vscsi_register);
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index 1780ffe..a954e7d 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -143,19 +143,21 @@ static Property spapr_vty_properties[] = {
 
 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 DeviceInfo spapr_vty_info = {
-    .name = "spapr-vty",
-    .size = sizeof(VIOsPAPRVTYDevice),
-    .props = spapr_vty_properties,
-    .class_init = spapr_vty_class_init,
+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)
@@ -214,6 +216,6 @@ static void spapr_vty_register(void)
 {
     spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
     spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
-    spapr_vio_bus_register_withprop(&spapr_vty_info);
+    type_register_static(&spapr_vty_info);
 }
 device_init(spapr_vty_register);
diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
index 582f2f0..f07cc6f 100644
--- a/hw/sparc32_dma.c
+++ b/hw/sparc32_dma.c
@@ -291,23 +291,25 @@ static Property sparc32_dma_properties[] = {
 
 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 DeviceInfo sparc32_dma_info = {
-    .name = "sparc32_dma",
-    .size = sizeof(DMAState),
-    .vmsd = &vmstate_dma,
-    .reset = dma_reset,
-    .props = sparc32_dma_properties,
-    .class_init = sparc32_dma_class_init,
+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 046efad..4e6540d 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -1031,17 +1031,19 @@ static Property sl_nand_properties[] = {
 
 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 DeviceInfo sl_nand_info = {
-    .name = "sl-nand",
-    .size = sizeof(SLNANDState),
-    .vmsd = &vmstate_sl_nand_info,
-    .props = sl_nand_properties,
-    .class_init = sl_nand_class_init,
+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 = {
@@ -1064,17 +1066,19 @@ static Property spitz_keyboard_properties[] = {
 
 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 DeviceInfo spitz_keyboard_info = {
-    .name = "spitz-keyboard",
-    .size = sizeof(SpitzKeyboardState),
-    .vmsd = &vmstate_spitz_kbd,
-    .props = spitz_keyboard_properties,
-    .class_init = spitz_keyboard_class_init,
+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 = {
@@ -1090,17 +1094,19 @@ static const VMStateDescription vmstate_corgi_ssp_regs = {
 
 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 DeviceInfo corgi_ssp_info = {
-    .name = "corgi-ssp",
-    .size = sizeof(CorgiSSPState),
-    .vmsd = &vmstate_corgi_ssp_regs,
-    .class_init = corgi_ssp_class_init,
+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 = {
@@ -1117,25 +1123,27 @@ static const VMStateDescription vmstate_spitz_lcdtg_regs = {
 
 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 DeviceInfo spitz_lcdtg_info = {
-    .name = "spitz-lcdtg",
-    .size = sizeof(SpitzLCDTG),
-    .vmsd = &vmstate_spitz_lcdtg_regs,
-    .class_init = spitz_lcdtg_class_init,
+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 acf027f..685602a 100644
--- a/hw/ssd0303.c
+++ b/hw/ssd0303.c
@@ -296,24 +296,26 @@ static int ssd0303_init(I2CSlave *i2c)
 
 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 DeviceInfo ssd0303_info = {
-    .name = "ssd0303",
-    .size = sizeof(ssd0303_state),
-    .vmsd = &vmstate_ssd0303,
-    .class_init = ssd0303_class_init,
+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 8e2fac8..3c43738 100644
--- a/hw/ssd0323.c
+++ b/hw/ssd0323.c
@@ -348,15 +348,16 @@ static void ssd0323_class_init(ObjectClass *klass, void *data)
     k->transfer = ssd0323_transfer;
 }
 
-static DeviceInfo ssd0323_info = {
-    .name = "ssd0323",
-    .size = sizeof(ssd0323_state),
-    .class_init = ssd0323_class_init,
+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 2738cf9..f2e6cec 100644
--- a/hw/ssi-sd.c
+++ b/hw/ssi-sd.c
@@ -252,15 +252,16 @@ static void ssi_sd_class_init(ObjectClass *klass, void *data)
     k->transfer = ssi_sd_transfer;
 }
 
-static DeviceInfo ssi_sd_info = {
-    .name = "ssi-sd",
-    .size = sizeof(ssi_sd_state),
-    .class_init = ssi_sd_class_init,
+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 994c922..4282b8b 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -36,14 +36,21 @@ static int ssi_slave_init(DeviceState *dev, DeviceInfo *base_info)
     return ssc->init(s);
 }
 
-void ssi_register_slave(DeviceInfo *info)
+static void ssi_slave_class_init(ObjectClass *klass, void *data)
 {
-    assert(info->size >= sizeof(SSISlave));
-    info->init = ssi_slave_init;
-    info->bus_info = &ssi_bus_info;
-    qdev_register_subclass(info, TYPE_SSI_SLAVE);
+    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;
@@ -72,3 +79,10 @@ uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
     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 97aefa7..06657d7 100644
--- a/hw/ssi.h
+++ b/hw/ssi.h
@@ -38,8 +38,6 @@ struct SSISlave {
 #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(DeviceInfo *info);
-
 DeviceState *ssi_create_slave(SSIBus *bus, const char *name);
 
 /* Master interface.  */
diff --git a/hw/stellaris.c b/hw/stellaris.c
index b91139e..31a65cf 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -1402,10 +1402,11 @@ static void stellaris_ssi_bus_class_init(ObjectClass *klass, void *data)
     k->transfer = stellaris_ssi_bus_transfer;
 }
 
-static DeviceInfo stellaris_ssi_bus_info = {
-    .name = "evb6965-ssi",
-    .size = sizeof(stellaris_ssi_bus_state),
-    .class_init = stellaris_ssi_bus_class_init,
+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)
@@ -1415,10 +1416,11 @@ static void stellaris_i2c_class_init(ObjectClass *klass, void *data)
     sdc->init = stellaris_i2c_init;
 }
 
-static DeviceInfo stellaris_i2c_info = {
-    .name = "stellaris-i2c",
-    .size = sizeof(stellaris_i2c_state),
-    .class_init = stellaris_i2c_class_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)
@@ -1428,10 +1430,11 @@ static void stellaris_gptm_class_init(ObjectClass *klass, void *data)
     sdc->init = stellaris_gptm_init;
 }
 
-static DeviceInfo stellaris_gptm_info = {
-    .name = "stellaris-gptm",
-    .size = sizeof(gptm_state),
-    .class_init = stellaris_gptm_class_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)
@@ -1441,18 +1444,19 @@ static void stellaris_adc_class_init(ObjectClass *klass, void *data)
     sdc->init = stellaris_adc_init;
 }
 
-static DeviceInfo stellaris_adc_info = {
-    .name = "stellaris-adc",
-    .size = sizeof(stellaris_adc_state),
-    .class_init = stellaris_adc_class_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_qdev_register(&stellaris_i2c_info);
-    sysbus_qdev_register(&stellaris_gptm_info);
-    sysbus_qdev_register(&stellaris_adc_info);
-    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 3d3ef66..9b1be8d 100644
--- a/hw/stellaris_enet.c
+++ b/hw/stellaris_enet.c
@@ -427,21 +427,23 @@ static Property stellaris_enet_properties[] = {
 
 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 DeviceInfo stellaris_enet_info = {
-    .name = "stellaris_enet",
-    .size = sizeof(stellaris_enet_state),
-    .props = stellaris_enet_properties,
-    .class_init = stellaris_enet_class_init,
+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 15828bf..8d2e7eb 100644
--- a/hw/strongarm.c
+++ b/hw/strongarm.c
@@ -203,17 +203,19 @@ static VMStateDescription 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 DeviceInfo strongarm_pic_info = {
-    .name = "strongarm_pic",
-    .desc = "StrongARM PIC",
-    .size = sizeof(StrongARMPICState),
-    .vmsd = &vmstate_strongarm_pic_regs,
-    .class_init = strongarm_pic_class_init,
+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 */
@@ -422,17 +424,19 @@ static const VMStateDescription 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 DeviceInfo strongarm_rtc_sysbus_info = {
-    .name = "strongarm-rtc",
-    .desc = "StrongARM RTC Controller",
-    .size = sizeof(StrongARMRTCState),
-    .vmsd = &vmstate_strongarm_rtc_regs,
-    .class_init = strongarm_rtc_sysbus_class_init,
+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 */
@@ -662,16 +666,18 @@ static const VMStateDescription vmstate_strongarm_gpio_regs = {
 
 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 DeviceInfo strongarm_gpio_info = {
-    .name = "strongarm-gpio",
-    .desc = "StrongARM GPIO controller",
-    .size = sizeof(StrongARMGPIOInfo),
-    .class_init = strongarm_gpio_class_init,
+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 */
@@ -826,16 +832,18 @@ static const VMStateDescription vmstate_strongarm_ppc_regs = {
 
 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 DeviceInfo strongarm_ppc_info = {
-    .name = "strongarm-ppc",
-    .desc = "StrongARM PPC controller",
-    .size = sizeof(StrongARMPPCInfo),
-    .class_init = strongarm_ppc_class_init,
+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 */
@@ -1280,19 +1288,21 @@ static Property strongarm_uart_properties[] = {
 
 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 DeviceInfo strongarm_uart_info = {
-    .name = "strongarm-uart",
-    .desc = "StrongARM UART controller",
-    .size = sizeof(StrongARMUARTState),
-    .reset = strongarm_uart_reset,
-    .vmsd = &vmstate_strongarm_uart_regs,
-    .props = strongarm_uart_properties,
-    .class_init = strongarm_uart_class_init,
+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 */
@@ -1518,18 +1528,20 @@ static const VMStateDescription 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 DeviceInfo strongarm_ssp_info = {
-    .name = "strongarm-ssp",
-    .desc = "StrongARM SSP controller",
-    .size = sizeof(StrongARMSSPState),
-    .reset = strongarm_ssp_reset,
-    .vmsd = &vmstate_strongarm_ssp_regs,
-    .class_init = strongarm_ssp_class_init,
+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 */
@@ -1599,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 111d31b..081d6cc 100644
--- a/hw/sun4c_intctl.c
+++ b/hw/sun4c_intctl.c
@@ -208,22 +208,24 @@ static int sun4c_intctl_init1(SysBusDevice *dev)
 
 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 DeviceInfo sun4c_intctl_info = {
-    .name = "sun4c_intctl",
-    .size = sizeof(Sun4c_INTCTLState),
-    .vmsd = &vmstate_sun4c_intctl,
-    .reset = sun4c_intctl_reset,
-    .class_init = sun4c_intctl_class_init,
+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 f2ff0bd..b79d14c 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -616,15 +616,16 @@ static void idreg_class_init(ObjectClass *klass, void *data)
     k->init = idreg_init1;
 }
 
-static DeviceInfo idreg_info = {
-    .name = "macio_idreg",
-    .size = sizeof(IDRegState),
-    .class_init = idreg_class_init,
+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);
@@ -664,15 +665,16 @@ static void afx_class_init(ObjectClass *klass, void *data)
     k->init = afx_init1;
 }
 
-static DeviceInfo afx_info = {
-    .name = "tcx_afx",
-    .size = sizeof(AFXState),
-    .class_init = afx_class_init,
+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);
@@ -740,21 +742,23 @@ static Property prom_properties[] = {
 
 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 DeviceInfo prom_info = {
-    .name = "openprom",
-    .size = sizeof(PROMState),
-    .props = prom_properties,
-    .class_init = prom_class_init,
+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);
@@ -809,21 +813,23 @@ static Property ram_properties[] = {
 
 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 DeviceInfo ram_info = {
-    .name = "memory",
-    .size = sizeof(RamDevice),
-    .props = ram_properties,
-    .class_init = ram_class_init,
+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 823bfac..727532c 100644
--- a/hw/sun4m_iommu.c
+++ b/hw/sun4m_iommu.c
@@ -364,23 +364,25 @@ static Property iommu_properties[] = {
 
 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 DeviceInfo iommu_info = {
-    .name = "iommu",
-    .size = sizeof(IOMMUState),
-    .vmsd = &vmstate_iommu,
-    .reset = iommu_reset,
-    .props = iommu_properties,
-    .class_init = iommu_class_init,
+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 f3bb226..79bbd49 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -573,15 +573,16 @@ static void ebus_class_init(ObjectClass *klass, void *data)
     k->class_id = PCI_CLASS_BRIDGE_OTHER;
 }
 
-static DeviceInfo ebus_info = {
-    .name = "ebus",
-    .size = sizeof(EbusState),
-    .class_init = ebus_class_init,
+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);
@@ -649,21 +650,23 @@ static Property prom_properties[] = {
 
 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 DeviceInfo prom_info = {
-    .name = "openprom",
-    .size = sizeof(PROMState),
-    .props = prom_properties,
-    .class_init = prom_class_init,
+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);
@@ -711,21 +714,23 @@ static Property ram_properties[] = {
 
 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 DeviceInfo ram_info = {
-    .name = "memory",
-    .size = sizeof(RamDevice),
-    .props = ram_properties,
-    .class_init = ram_class_init,
+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 7d122f9..4870dbf 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -113,20 +113,6 @@ static int sysbus_device_init(DeviceState *dev, DeviceInfo *base)
     return sbc->init(sd);
 }
 
-void sysbus_qdev_register_subclass(DeviceInfo *info, const char *parent)
-{
-    info->init = sysbus_device_init;
-    info->bus_info = &system_bus_info;
-
-    assert(info->size >= sizeof(SysBusDevice));
-    qdev_register_subclass(info, parent);
-}
-
-void sysbus_qdev_register(DeviceInfo *info)
-{
-    sysbus_qdev_register_subclass(info, TYPE_SYS_BUS_DEVICE);
-}
-
 DeviceState *sysbus_create_varargs(const char *name,
                                    target_phys_addr_t addr, ...)
 {
@@ -254,12 +240,20 @@ 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)
diff --git a/hw/sysbus.h b/hw/sysbus.h
index a406077..22555cd 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -44,10 +44,6 @@ struct SysBusDevice {
 #define sysbus_from_qdev(dev) ((SysBusDevice *)(dev))
 #define FROM_SYSBUS(type, dev) DO_UPCAST(type, busdev, dev)
 
-#define sysbus_register_withprop(info) sysbus_qdev_register(info)
-void sysbus_qdev_register(DeviceInfo *info);
-void sysbus_qdev_register_subclass(DeviceInfo *info, const char *parent);
-
 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 7743c05..f400f92 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -649,23 +649,25 @@ static Property tcx_properties[] = {
 
 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 DeviceInfo tcx_info = {
-    .name = "SUNW,tcx",
-    .size = sizeof(TCXState),
-    .reset = tcx_reset,
-    .vmsd = &vmstate_tcx,
-    .props = tcx_properties,
-    .class_init = tcx_class_init,
+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 12fe60d..a3bdd91 100644
--- a/hw/tmp105.c
+++ b/hw/tmp105.c
@@ -228,24 +228,26 @@ static int tmp105_init(I2CSlave *i2c)
 
 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 DeviceInfo tmp105_info = {
-    .name = "tmp105",
-    .size = sizeof(TMP105State),
-    .vmsd = &vmstate_tmp105,
-    .class_init = tmp105_class_init,
+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 9f112b1..c0d4017 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -269,11 +269,12 @@ static void tosa_dac_class_init(ObjectClass *klass, void *data)
     k->send = tosa_dac_send;
 }
 
-static DeviceInfo tosa_dac_info = {
-    .name = "tosa_dac",
-    .size = sizeof(TosaDACState),
-    .class_init = tosa_dac_class_init,
- };
+static TypeInfo tosa_dac_info = {
+    .name          = "tosa_dac",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(TosaDACState),
+    .class_init    = tosa_dac_class_init,
+};
 
 static void tosa_ssp_class_init(ObjectClass *klass, void *data)
 {
@@ -283,16 +284,17 @@ static void tosa_ssp_class_init(ObjectClass *klass, void *data)
     k->transfer = tosa_ssp_tansfer;
 }
 
-static DeviceInfo tosa_ssp_info = {
-    .name = "tosa-ssp",
-    .size = sizeof(SSISlave),
-    .class_init = tosa_ssp_class_init,
+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 8e11c54..0ade670 100644
--- a/hw/tusb6010.c
+++ b/hw/tusb6010.c
@@ -791,21 +791,23 @@ static int tusb6010_init(SysBusDevice *dev)
 
 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 DeviceInfo tusb6010_info = {
-    .name = "tusb6010",
-    .size = sizeof(TUSBState),
-    .reset = tusb6010_reset,
-    .class_init = tusb6010_class_init,
+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 ba4f8aa..03fdccc 100644
--- a/hw/twl92230.c
+++ b/hw/twl92230.c
@@ -859,24 +859,26 @@ static int twl92230_init(I2CSlave *i2c)
 
 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 DeviceInfo twl92230_info = {
-    .name ="twl92230",
-    .size = sizeof(MenelausState),
-    .vmsd = &vmstate_menelaus,
-    .class_init = twl92230_class_init,
+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 9822353..17d86aa 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -350,9 +350,10 @@ static void unin_main_pci_host_class_init(ObjectClass *klass, void *data)
     k->class_id  = PCI_CLASS_BRIDGE_HOST;
 }
 
-static DeviceInfo unin_main_pci_host_info = {
+static TypeInfo unin_main_pci_host_info = {
     .name = "uni-north-pci",
-    .size = sizeof(PCIDevice),
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
     .class_init = unin_main_pci_host_class_init,
 };
 
@@ -367,9 +368,10 @@ static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data)
     k->class_id  = PCI_CLASS_BRIDGE_HOST;
 }
 
-static DeviceInfo u3_agp_pci_host_info = {
+static TypeInfo u3_agp_pci_host_info = {
     .name = "u3-agp",
-    .size = sizeof(PCIDevice),
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
     .class_init = u3_agp_pci_host_class_init,
 };
 
@@ -384,9 +386,10 @@ static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data)
     k->class_id  = PCI_CLASS_BRIDGE_HOST;
 }
 
-static DeviceInfo unin_agp_pci_host_info = {
+static TypeInfo unin_agp_pci_host_info = {
     .name = "uni-north-agp",
-    .size = sizeof(PCIDevice),
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
     .class_init = unin_agp_pci_host_class_init,
 };
 
@@ -401,9 +404,10 @@ static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data)
     k->class_id  = PCI_CLASS_BRIDGE_HOST;
 }
 
-static DeviceInfo unin_internal_pci_host_info = {
+static TypeInfo unin_internal_pci_host_info = {
     .name = "uni-north-internal-pci",
-    .size = sizeof(PCIDevice),
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
     .class_init = unin_internal_pci_host_class_init,
 };
 
@@ -414,10 +418,11 @@ static void pci_unin_main_class_init(ObjectClass *klass, void *data)
     sbc->init = pci_unin_main_init_device;
 }
 
-static DeviceInfo pci_unin_main_info = {
-    .name = "uni-north-pci-pcihost",
-    .size = sizeof(UNINState),
-    .class_init = pci_unin_main_class_init,
+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)
@@ -427,10 +432,11 @@ static void pci_u3_agp_class_init(ObjectClass *klass, void *data)
     sbc->init = pci_u3_agp_init_device;
 }
 
-static DeviceInfo pci_u3_agp_info = {
-    .name = "u3-agp-pcihost",
-    .size = sizeof(UNINState),
-    .class_init = pci_u3_agp_class_init,
+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 void pci_unin_agp_class_init(ObjectClass *klass, void *data)
@@ -440,10 +446,11 @@ static void pci_unin_agp_class_init(ObjectClass *klass, void *data)
     sbc->init = pci_unin_agp_init_device;
 }
 
-static DeviceInfo pci_unin_agp_info = {
-    .name = "uni-north-agp-pcihost",
-    .size = sizeof(UNINState),
-    .class_init = pci_unin_agp_class_init,
+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 void pci_unin_internal_class_init(ObjectClass *klass, void *data)
@@ -453,23 +460,24 @@ static void pci_unin_internal_class_init(ObjectClass *klass, void *data)
     sbc->init = pci_unin_internal_init_device;
 }
 
-static DeviceInfo pci_unin_internal_info = {
-    .name = "uni-north-internal-pci-pcihost",
-    .size = sizeof(UNINState),
-    .class_init = pci_unin_internal_class_init,
+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)
 {
-    pci_qdev_register(&unin_main_pci_host_info);
-    pci_qdev_register(&u3_agp_pci_host_info);
-    pci_qdev_register(&unin_agp_pci_host_info);
-    pci_qdev_register(&unin_internal_pci_host_info);
-
-    sysbus_register_withprop(&pci_unin_main_info);
-    sysbus_register_withprop(&pci_u3_agp_info);
-    sysbus_register_withprop(&pci_unin_agp_info);
-    sysbus_register_withprop(&pci_unin_internal_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
index 459f162..cd589b7 100644
--- a/hw/usb-audio.c
+++ b/hw/usb-audio.c
@@ -674,10 +674,20 @@ static const VMStateDescription vmstate_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;
@@ -689,22 +699,16 @@ static void usb_audio_class_init(ObjectClass *klass, void *data)
     k->set_interface  = usb_audio_set_interface;
 }
 
-static struct DeviceInfo usb_audio_info = {
-    .name      = "usb-audio",
-    .size      = sizeof(USBAudioState),
-    .vmsd      = &vmstate_usb_audio,
-    .class_init = usb_audio_class_init,
-    .props = (Property[]) {
-        DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0),
-        DEFINE_PROP_UINT32("buffer", USBAudioState, buffer,
-                           8 * USBAUDIO_PACKET_SIZE),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+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)
 {
-    usb_qdev_register(&usb_audio_info);
+    type_register_static(&usb_audio_info);
     usb_legacy_register("usb-audio", "audio", NULL);
 }
 
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index f497a44..90c3b0e 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -529,6 +529,7 @@ static const VMStateDescription vmstate_usb_bt = {
 
 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;
@@ -539,17 +540,18 @@ static void usb_bt_class_initfn(ObjectClass *klass, void *data)
     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 struct DeviceInfo bt_info = {
-    .name      = "usb-bt-dongle",
-    .size      = sizeof(struct USBBtState),
-    .vmsd      = &vmstate_usb_bt,
-    .class_init= usb_bt_class_initfn,
+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 6b0adfd..d07f844 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -220,15 +220,6 @@ void usb_legacy_register(const char *typename, const char *usbdevice_name,
     }
 }
 
-void usb_qdev_register(DeviceInfo *info)
-{
-    info->bus_info = &usb_bus_info;
-    info->init     = usb_qdev_init;
-    info->unplug   = qdev_simple_unplug_cb;
-    info->exit     = usb_qdev_exit;
-    qdev_register_subclass(info, TYPE_USB_DEVICE);
-}
-
 USBDevice *usb_create(USBBus *bus, const char *name)
 {
     DeviceState *dev;
@@ -577,12 +568,22 @@ USBDevice *usbdevice_create(const char *cmdline)
     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)
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index a261d7d..844f873 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -1184,14 +1184,6 @@ static int ccid_card_init(DeviceState *qdev, DeviceInfo *base)
     return ret;
 }
 
-void ccid_card_qdev_register(DeviceInfo *info)
-{
-    info->bus_info = &ccid_bus_info;
-    info->init = ccid_card_init;
-    info->exit = ccid_card_exit;
-    qdev_register_subclass(info, TYPE_CCID_CARD);
-}
-
 static int ccid_initfn(USBDevice *dev)
 {
     USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
@@ -1315,8 +1307,14 @@ static VMStateDescription 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;
@@ -1327,32 +1325,39 @@ static void ccid_class_initfn(ObjectClass *klass, void *data)
     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 struct DeviceInfo ccid_info = {
-    .name      = CCID_DEV_NAME,
-    .desc      = "CCID Rev 1.1 smartcard reader",
-    .size      = sizeof(USBCCIDState),
-    .class_init= ccid_class_initfn,
-    .vmsd      = &ccid_vmstate,
-    .props     = (Property[]) {
-        DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+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)
 {
     type_register_static(&ccid_card_type_info);
-    usb_qdev_register(&ccid_info);
+    type_register_static(&ccid_info);
     usb_legacy_register(CCID_DEV_NAME, "ccid", NULL);
 }
 device_init(ccid_register_devices)
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 8baff1d..75ef71e 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -2265,6 +2265,7 @@ static Property ehci_properties[] = {
 
 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;
@@ -2272,18 +2273,20 @@ static void ehci_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo ehci_info = {
-    .name = "usb-ehci",
-    .size = sizeof(EHCIState),
-    .vmsd = &vmstate_ehci,
-    .props = ehci_properties,
-    .class_init = ehci_class_init,
+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;
@@ -2291,14 +2294,15 @@ static void ich9_ehci_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo ich9_ehci_info = {
-    .name = "ich9-usb-ehci1",
-    .size = sizeof(EHCIState),
-    .vmsd = &vmstate_ehci,
-    .props = ehci_properties,
-    .class_init = ich9_ehci_class_init,
+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)
@@ -2374,8 +2378,8 @@ static int usb_ehci_initfn(PCIDevice *dev)
 
 static void ehci_register(void)
 {
-    pci_qdev_register(&ehci_info);
-    pci_qdev_register(&ich9_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 669aae4..3c4e45d 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -566,62 +566,68 @@ static void usb_hid_class_initfn(ObjectClass *klass, void *data)
 
 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 struct DeviceInfo usb_tablet_info = {
-    .name      = "usb-tablet",
-    .size      = sizeof(USBHIDState),
-    .vmsd      = &vmstate_usb_ptr,
-    .class_init= usb_tablet_class_initfn,
+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 struct DeviceInfo usb_mouse_info = {
-    .name      = "usb-mouse",
-    .size      = sizeof(USBHIDState),
-    .vmsd      = &vmstate_usb_ptr,
-    .class_init= usb_mouse_class_initfn,
+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 struct DeviceInfo usb_keyboard_info = {
-    .name      = "usb-kbd",
-    .size      = sizeof(USBHIDState),
-    .vmsd      = &vmstate_usb_kbd,
-    .class_init= usb_keyboard_class_initfn,
+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(&usb_tablet_info);
+    type_register_static(&usb_tablet_info);
     usb_legacy_register("usb-tablet", "tablet", NULL);
-    usb_qdev_register(&usb_mouse_info);
+    type_register_static(&usb_mouse_info);
     usb_legacy_register("usb-mouse", "mouse", NULL);
-    usb_qdev_register(&usb_keyboard_info);
+    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 3e33685..956b020 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -533,8 +533,9 @@ static const VMStateDescription vmstate_usb_hub = {
     }
 };
 
-static void  usb_hub_class_initfn(ObjectClass *klass, void *data)
+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;
@@ -545,18 +546,19 @@ static void  usb_hub_class_initfn(ObjectClass *klass, void *data)
     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 struct DeviceInfo hub_info = {
-    .name      = "usb-hub",
-    .fw_name   = "hub",
-    .size      = sizeof(USBHubState),
-    .vmsd      = &vmstate_usb_hub,
-    .class_init= usb_hub_class_initfn,
+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 19d0d7b..6153376 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -636,8 +636,16 @@ static const VMStateDescription vmstate_usb_msd = {
     }
 };
 
+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;
@@ -649,25 +657,21 @@ static void usb_msd_class_initfn(ObjectClass *klass, void *data)
     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 struct DeviceInfo msd_info = {
-    .name      = "usb-storage",
-    .fw_name   = "storage",
-    .size      = sizeof(MSDState),
-    .vmsd      = &vmstate_usb_msd,
-    .class_init= usb_msd_class_initfn,
-    .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 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-net.c b/hw/usb-net.c
index 65eee95..e211141 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1385,8 +1385,14 @@ static const VMStateDescription vmstate_usb_net = {
     .unmigratable = 1,
 };
 
+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;
@@ -1397,23 +1403,21 @@ static void usb_net_class_initfn(ObjectClass *klass, void *data)
     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 struct DeviceInfo net_info = {
-    .name      = "usb-net",
-    .fw_name   = "network",
-    .size      = sizeof(USBNetState),
-    .vmsd      = &vmstate_usb_net,
-    .class_init= usb_net_class_initfn,
-    .props     = (Property[]) {
-        DEFINE_NIC_PROPERTIES(USBNetState, conf),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+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 3437da1..425030f 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1845,44 +1845,50 @@ static Property ohci_pci_properties[] = {
 
 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 DeviceInfo ohci_pci_info = {
-    .name = "pci-ohci",
-    .desc = "Apple USB Controller",
-    .size = sizeof(OHCIPCIState),
-    .props = ohci_pci_properties,
-    .class_init = ohci_pci_class_init,
+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 DeviceInfo ohci_sysbus_info = {
-    .name    = "sysbus-ohci",
-    .desc    = "OHCI USB Controller",
-    .size    = sizeof(OHCISysBusState),
-    .class_init = ohci_sysbus_class_init,
-    .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 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 00b4985..c2cb6d2 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -570,8 +570,14 @@ static const VMStateDescription vmstate_usb_serial = {
     .unmigratable = 1,
 };
 
+static Property serial_properties[] = {
+    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;
@@ -582,21 +588,25 @@ static void usb_serial_class_initfn(ObjectClass *klass, void *data)
     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 struct DeviceInfo serial_info = {
-    .name      = "usb-serial",
-    .size      = sizeof(USBSerialState),
-    .vmsd      = &vmstate_usb_serial,
-    .class_init= usb_serial_class_initfn,
-    .props     = (Property[]) {
-        DEFINE_PROP_CHR("chardev", USBSerialState, cs),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+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;
@@ -607,24 +617,22 @@ static void usb_braille_class_initfn(ObjectClass *klass, void *data)
     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 struct DeviceInfo braille_info = {
-    .name      = "usb-braille",
-    .size      = sizeof(USBSerialState),
-    .vmsd      = &vmstate_usb_serial,
-    .class_init= usb_braille_class_initfn,
-    .props     = (Property[]) {
-        DEFINE_PROP_CHR("chardev", USBSerialState, cs),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+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);
+    type_register_static(&serial_info);
     usb_legacy_register("usb-serial", "serial", usb_serial_init);
-    usb_qdev_register(&braille_info);
+    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 e20d7c4..cddcc89 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -1194,6 +1194,7 @@ static Property uhci_properties[] = {
 
 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;
@@ -1202,18 +1203,20 @@ static void piix3_uhci_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo piix3_uhci_info = {
-    .name = "piix3-usb-uhci",
-    .size = sizeof(UHCIState),
-    .vmsd = &vmstate_uhci,
-    .props = uhci_properties,
-    .class_init = piix3_uhci_class_init,
+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;
@@ -1222,18 +1225,20 @@ static void piix4_uhci_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo piix4_uhci_info = {
-    .name = "piix4-usb-uhci",
-    .size = sizeof(UHCIState),
-    .vmsd = &vmstate_uhci,
-    .props = uhci_properties,
-    .class_init = piix4_uhci_class_init,
+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;
@@ -1242,18 +1247,20 @@ static void vt82c686b_uhci_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo vt82c686b_uhci_info = {
-    .name = "vt82c686b-usb-uhci",
-    .size = sizeof(UHCIState),
-    .vmsd = &vmstate_uhci,
-    .props = uhci_properties,
-    .class_init = vt82c686b_uhci_class_init,
+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;
@@ -1261,18 +1268,20 @@ static void ich9_uhci1_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo ich9_uhci1_info = {
-    .name = "ich9-usb-uhci1",
-    .size = sizeof(UHCIState),
-    .vmsd = &vmstate_uhci,
-    .props = uhci_properties,
-    .class_init = ich9_uhci1_class_init,
+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;
@@ -1280,18 +1289,20 @@ static void ich9_uhci2_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo ich9_uhci2_info = {
-    .name = "ich9-usb-uhci2",
-    .size = sizeof(UHCIState),
-    .vmsd = &vmstate_uhci,
-    .props = uhci_properties,
-    .class_init = ich9_uhci2_class_init,
+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;
@@ -1299,24 +1310,25 @@ static void ich9_uhci3_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo ich9_uhci3_info = {
-    .name = "ich9-usb-uhci3",
-    .size = sizeof(UHCIState),
-    .vmsd = &vmstate_uhci,
-    .props = uhci_properties,
-    .class_init = ich9_uhci3_class_init,
+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(&piix3_uhci_info);
-    pci_qdev_register(&piix4_uhci_info);
-    pci_qdev_register(&vt82c686b_uhci_info);
-    pci_qdev_register(&ich9_uhci1_info);
-    pci_qdev_register(&ich9_uhci2_info);
-    pci_qdev_register(&ich9_uhci3_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 40bb199..14de14d 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -349,9 +349,10 @@ static const VMStateDescription vmstate_usb_wacom = {
     .unmigratable = 1,
 };
 
-static void usb_wacom_class_init(ObjectClass *class, void *data)
+static void usb_wacom_class_init(ObjectClass *klass, void *data)
 {
-    USBDeviceClass *uc = USB_DEVICE_CLASS(class);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
 
     uc->product_desc   = "QEMU PenPartner Tablet";
     uc->usb_desc       = &desc_wacom;
@@ -361,19 +362,20 @@ static void usb_wacom_class_init(ObjectClass *class, void *data)
     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 struct DeviceInfo wacom_info = {
-    .name      = "usb-wacom-tablet",
-    .desc      = "QEMU PenPartner Tablet",
-    .size      = sizeof(USBWacomState),
-    .vmsd      = &vmstate_usb_wacom,
-    .class_init= usb_wacom_class_init,
+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
index fba2de3..37e887c 100644
--- a/hw/usb-xhci.c
+++ b/hw/usb-xhci.c
@@ -2724,10 +2724,18 @@ static const VMStateDescription vmstate_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;
@@ -2737,20 +2745,15 @@ static void xhci_class_init(ObjectClass *klass, void *data)
     k->config_write = xhci_write_config;
 }
 
-static DeviceInfo xhci_info = {
-    .name    = "nec-usb-xhci",
-    .alias   = "xhci",
-    .size    = sizeof(XHCIState),
-    .vmsd    = &vmstate_xhci,
-    .class_init   = xhci_class_init,
-    .props   = (Property[]) {
-        DEFINE_PROP_UINT32("msi", XHCIState, msi, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+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)
 {
-    pci_qdev_register(&xhci_info);
+    type_register_static(&xhci_info);
 }
 device_init(xhci_register);
diff --git a/hw/usb.h b/hw/usb.h
index b9b6742..13e7c8e 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -418,7 +418,6 @@ struct USBBusOps {
 
 void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
 USBBus *usb_bus_find(int busnr);
-void usb_qdev_register(DeviceInfo *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);
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index c2eb4dd..c4105e9 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -119,10 +119,11 @@ static void versatile_pci_host_class_init(ObjectClass *klass, void *data)
     k->class_id = PCI_CLASS_PROCESSOR_CO;
 }
 
-static DeviceInfo versatile_pci_host_info = {
-    .name = "versatile_pci_host",
-    .size = sizeof(PCIDevice),
-    .class_init = versatile_pci_host_class_init,
+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)
@@ -132,10 +133,11 @@ static void pci_vpb_class_init(ObjectClass *klass, void *data)
     sdc->init = pci_vpb_init;
 }
 
-static DeviceInfo pci_vpb_info = {
-    .name = "versatile_pci",
-    .size = sizeof(PCIVPBState),
-    .class_init = pci_vpb_class_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)
@@ -145,17 +147,18 @@ static void pci_realview_class_init(ObjectClass *klass, void *data)
     sdc->init = pci_realview_init;
 }
 
-static DeviceInfo pci_realview_info = {
-    .name = "realview_pci",
-    .size = sizeof(PCIVPBState),
-    .class_init = pci_realview_class_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_qdev_register(&pci_vpb_info);
-    sysbus_qdev_register(&pci_realview_info);
-    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 3f7490c..6e28e78 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -367,22 +367,24 @@ machine_init(versatile_machine_init);
 
 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 DeviceInfo vpb_sic_info = {
-    .name = "versatilepb_sic",
-    .size = sizeof(vpb_sic_state),
-    .vmsd = &vmstate_vpb_sic,
-    .no_user = 1,
-    .class_init = vpb_sic_class_init,
+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/vga-isa.c b/hw/vga-isa.c
index cb6af91..8d3ff0d 100644
--- a/hw/vga-isa.c
+++ b/hw/vga-isa.c
@@ -71,20 +71,22 @@ static int vga_initfn(ISADevice *dev)
 
 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 DeviceInfo vga_info = {
-    .name     = "isa-vga",
-    .size     = sizeof(ISAVGAState),
-    .vmsd     = &vmstate_vga_common,
-    .reset     = vga_reset_isa,
-    .class_init          = vga_class_initfn,
+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 ef9f8a5..974a7a9 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -77,6 +77,7 @@ DeviceState *pci_vga_init(PCIBus *bus)
 
 static void vga_class_init(ObjectClass *klass, void *data)
 {
+    DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
     k->no_hotplug = 1;
@@ -85,17 +86,18 @@ static void vga_class_init(ObjectClass *klass, void *data)
     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;
 }
 
-static DeviceInfo vga_info = {
-    .name = "VGA",
-    .size = sizeof(PCIVGAState),
-    .vmsd = &vmstate_vga_pci,
-    .class_init = vga_class_init,
+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/virtio-console.c b/hw/virtio-console.c
index 73c3935..4f2c3e4 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -131,6 +131,7 @@ static Property virtconsole_properties[] = {
 
 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;
@@ -138,18 +139,19 @@ static void virtconsole_class_init(ObjectClass *klass, void *data)
     k->have_data = flush_buf;
     k->guest_open = guest_open;
     k->guest_close = guest_close;
+    dc->props = virtconsole_properties;
 }
 
-static DeviceInfo virtconsole_info = {
-    .name = "virtconsole",
-    .size = sizeof(VirtConsole),
-    .props = virtconsole_properties,
-    .class_init = virtconsole_class_init,
+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)
 
@@ -160,23 +162,25 @@ static Property virtserialport_properties[] = {
 
 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 DeviceInfo virtserialport_info = {
-    .name = "virtserialport",
-    .size = sizeof(VirtConsole),
-    .props = virtserialport_properties,
-    .class_init = virtserialport_class_init,
+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-pci.c b/hw/virtio-pci.c
index 126fb08..bc96552 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -818,6 +818,7 @@ static Property virtio_blk_properties[] = {
 
 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;
@@ -826,15 +827,16 @@ static void virtio_blk_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
     k->revision = VIRTIO_PCI_ABI_VERSION;
     k->class_id = PCI_CLASS_STORAGE_SCSI;
+    dc->alias = "virtio-blk";
+    dc->reset = virtio_pci_reset;
+    dc->props = virtio_blk_properties;
 }
 
-static DeviceInfo virtio_blk_info = {
-    .name = "virtio-blk-pci",
-    .alias = "virtio-blk",
-    .size = sizeof(VirtIOPCIProxy),
-    .props = virtio_blk_properties,
-    .reset = virtio_pci_reset,
-    .class_init = virtio_blk_class_init,
+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[] = {
@@ -850,6 +852,7 @@ static Property virtio_net_properties[] = {
 
 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;
@@ -859,15 +862,16 @@ static void virtio_net_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
     k->revision = VIRTIO_PCI_ABI_VERSION;
     k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+    dc->alias = "virtio-net";
+    dc->reset = virtio_pci_reset;
+    dc->props = virtio_net_properties;
 }
 
-static DeviceInfo virtio_net_info = {
-    .name = "virtio-net-pci",
-    .alias = "virtio-net",
-    .size = sizeof(VirtIOPCIProxy),
-    .props = virtio_net_properties,
-    .reset = virtio_pci_reset,
-    .class_init = virtio_net_class_init,
+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[] = {
@@ -881,6 +885,7 @@ static Property virtio_serial_properties[] = {
 
 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;
@@ -889,15 +894,16 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
     k->revision = VIRTIO_PCI_ABI_VERSION;
     k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
+    dc->alias = "virtio-serial";
+    dc->reset = virtio_pci_reset;
+    dc->props = virtio_serial_properties;
 }
 
-static DeviceInfo virtio_serial_info = {
-    .name = "virtio-serial-pci",
-    .alias = "virtio-serial",
-    .size = sizeof(VirtIOPCIProxy),
-    .props = virtio_serial_properties,
-    .reset = virtio_pci_reset,
-    .class_init = virtio_serial_class_init,
+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[] = {
@@ -907,6 +913,7 @@ static Property virtio_balloon_properties[] = {
 
 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;
@@ -915,23 +922,28 @@ static void virtio_balloon_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
     k->revision = VIRTIO_PCI_ABI_VERSION;
     k->class_id = PCI_CLASS_MEMORY_RAM;
+    dc->alias = "virtio-balloon";
+    dc->reset = virtio_pci_reset;
+    dc->props = virtio_balloon_properties;
 }
 
-static DeviceInfo virtio_balloon_info = {
-    .name = "virtio-balloon-pci",
-    .alias = "virtio-balloon",
-    .size = sizeof(VirtIOPCIProxy),
-    .props = virtio_balloon_properties,
-    .reset = virtio_pci_reset,
-    .class_init = virtio_balloon_class_init,
+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(&virtio_blk_info);
-    pci_qdev_register(&virtio_net_info);
-    pci_qdev_register(&virtio_serial_info);
-    pci_qdev_register(&virtio_balloon_info);
+    type_register_static(&virtio_blk_info);
+    type_register_static_alias(&virtio_blk_info, "virtio-blk");
+    type_register_static(&virtio_net_info);
+    type_register_static_alias(&virtio_net_info, "virtio-net");
+    type_register_static(&virtio_serial_info);
+    type_register_static_alias(&virtio_serial_info, "virtio-serial");
+    type_register_static(&virtio_balloon_info);
+    type_register_static_alias(&virtio_balloon_info, "virtio-balloon");
 }
 
 device_init(virtio_pci_register_devices)
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 70f5d48..50a6d7f 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -837,15 +837,6 @@ static int virtser_port_qdev_exit(DeviceState *qdev)
     return 0;
 }
 
-void virtio_serial_port_qdev_register(DeviceInfo *info)
-{
-    info->init = virtser_port_qdev_init;
-    info->bus_info = &virtser_bus_info;
-    info->exit = virtser_port_qdev_exit;
-    info->unplug = qdev_simple_unplug_cb;
-    qdev_register_subclass(info, TYPE_VIRTIO_SERIAL_PORT);
-}
-
 VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
 {
     VirtIOSerial *vser;
@@ -940,12 +931,22 @@ 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)
diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h
index 6207c89..16e3982 100644
--- a/hw/virtio-serial.h
+++ b/hw/virtio-serial.h
@@ -176,12 +176,6 @@ struct VirtIOSerialPort {
 /* 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(DeviceInfo *info);
-
-/*
  * Open a connection to the port
  *   Returns 0 on success (always).
  */
diff --git a/hw/vmmouse.c b/hw/vmmouse.c
index 5c80bc4..fda4f89 100644
--- a/hw/vmmouse.c
+++ b/hw/vmmouse.c
@@ -271,27 +271,31 @@ static int vmmouse_initfn(ISADevice *dev)
     return 0;
 }
 
+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 DeviceInfo vmmouse_info = {
-    .class_init          = vmmouse_class_initfn,
-    .name     = "vmmouse",
-    .size     = sizeof(VMMouseState),
-    .vmsd     = &vmstate_vmmouse,
-    .no_user  = 1,
-    .reset    = vmmouse_reset,
-    .props = (Property[]) {
-        DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+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 c4582d6..a2c45e1 100644
--- a/hw/vmport.c
+++ b/hw/vmport.c
@@ -146,19 +146,21 @@ static int vmport_initfn(ISADevice *dev)
 
 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 DeviceInfo vmport_info = {
-    .name     = "vmport",
-    .size     = sizeof(VMPortState),
-    .no_user  = 1,
-    .class_init          = vmport_class_initfn,
+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 e7bbf7c..3f3eb21 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1201,6 +1201,7 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
 
 static void vmsvga_class_init(ObjectClass *klass, void *data)
 {
+    DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
     k->no_hotplug = 1;
@@ -1211,18 +1212,19 @@ static void vmsvga_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo vmsvga_info = {
-    .name = "vmware-svga",
-    .size = sizeof(struct pci_vmsvga_state_s),
-    .vmsd = &vmstate_vmware_vga,
-    .reset = vmsvga_reset,
-    .class_init = vmsvga_class_init,
+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/vt82c686.c b/hw/vt82c686.c
index 72be4fd..aa0954f 100644
--- a/hw/vt82c686.c
+++ b/hw/vt82c686.c
@@ -348,6 +348,7 @@ void vt82c686b_ac97_init(PCIBus *bus, int devfn)
 
 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;
@@ -355,18 +356,19 @@ static void via_ac97_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_VIA_AC97;
     k->revision = 0x50;
     k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
+    dc->desc = "AC97";
 }
 
-static DeviceInfo via_ac97_info = {
-    .name = "VT82C686B_AC97",
-    .desc = "AC97",
-    .size = sizeof(VT686AC97State),
-    .class_init = via_ac97_class_init,
+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);
@@ -394,6 +396,7 @@ void vt82c686b_mc97_init(PCIBus *bus, int devfn)
 
 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;
@@ -401,18 +404,19 @@ static void via_mc97_class_init(ObjectClass *klass, void *data)
     k->device_id = PCI_DEVICE_ID_VIA_MC97;
     k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
     k->revision = 0x30;
+    dc->desc = "MC97";
 }
 
-static DeviceInfo via_mc97_info = {
-    .name = "VT82C686B_MC97",
-    .desc = "MC97",
-    .size = sizeof(VT686MC97State),
-    .class_init = via_mc97_class_init,
+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);
@@ -472,6 +476,7 @@ static Property via_pm_properties[] = {
 
 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;
@@ -480,20 +485,21 @@ static void via_pm_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo via_pm_info = {
-    .name = "VT82C686B_PM",
-    .desc = "PM",
-    .size = sizeof(VT686PMState),
-    .vmsd = &vmstate_acpi,
-    .props = via_pm_properties,
-    .class_init = via_pm_class_init,
+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);
@@ -544,6 +550,7 @@ ISABus *vt82c686b_init(PCIBus *bus, int devfn)
 
 static void via_class_init(ObjectClass *klass, void *data)
 {
+    DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
     k->init = vt82c686b_initfn;
@@ -552,19 +559,20 @@ static void via_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo via_info = {
-    .name = "VT82C686B",
-    .desc = "ISA bridge",
-    .size = sizeof(VT82C686BState),
-    .vmsd = &vmstate_via,
-    .no_user = 1,
-    .class_init = via_class_init,
+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 a6ceff8..41325f0 100644
--- a/hw/wdt_i6300esb.c
+++ b/hw/wdt_i6300esb.c
@@ -427,6 +427,7 @@ static WatchdogTimerModel model = {
 
 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;
@@ -436,20 +437,21 @@ static void i6300esb_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo i6300esb_info = {
-    .name = "i6300esb",
-    .size = sizeof(I6300State),
-    .vmsd = &vmstate_i6300esb,
-    .reset = i6300esb_reset,
-    .class_init = i6300esb_class_init,
+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 6deb0de..8faa231 100644
--- a/hw/wdt_ib700.c
+++ b/hw/wdt_ib700.c
@@ -122,22 +122,24 @@ static WatchdogTimerModel model = {
 
 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 DeviceInfo wdt_ib700_info = {
-    .name  = "ib700",
-    .size  = sizeof(IB700State),
-    .vmsd  = &vmstate_ib700,
-    .reset = wdt_ib700_reset,
-    .class_init       = wdt_ib700_class_init,
+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 33bce0d..18afa4c 100644
--- a/hw/wm8750.c
+++ b/hw/wm8750.c
@@ -691,24 +691,26 @@ void wm8750_set_bclk_in(void *opaque, int new_hz)
 
 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 DeviceInfo wm8750_info = {
-    .name = "wm8750",
-    .size = sizeof(WM8750State),
-    .vmsd = &vmstate_wm8750,
-    .class_init = wm8750_class_init,
+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 40687fb..e757102 100644
--- a/hw/xen_platform.c
+++ b/hw/xen_platform.c
@@ -374,6 +374,7 @@ static void platform_reset(DeviceState *dev)
 
 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;
@@ -383,20 +384,21 @@ static void xen_platform_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo xen_platform_info = {
-    .name = "xen-platform",
-    .desc = "XEN platform pci device",
-    .size = sizeof(PCIXenPlatformState),
-    .vmsd = &vmstate_xen_platform,
-    .reset = platform_reset,
-    .class_init = xen_platform_class_init,
+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
index 73840c9..d395b1c 100644
--- a/hw/xgmac.c
+++ b/hw/xgmac.c
@@ -403,26 +403,31 @@ static int xgmac_enet_init(SysBusDevice *dev)
     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 DeviceInfo xgmac_enet_info = {
-    .name  = "xgmac",
-    .size  = sizeof(struct XgmacState),
-    .vmsd = &vmstate_xgmac,
-    .class_init = xgmac_enet_class_init,
-    .props = (Property[]) {
-        DEFINE_NIC_PROPERTIES(struct XgmacState, conf),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+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)
 {
-    sysbus_register_withprop(&xgmac_enet_info);
+    type_register_static(&xgmac_enet_info);
 }
 
 device_init(xgmac_enet_register)
diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c
index 0fbe415..e8a5312 100644
--- a/hw/xilinx_axidma.c
+++ b/hw/xilinx_axidma.c
@@ -494,21 +494,23 @@ static Property axidma_properties[] = {
 
 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 DeviceInfo axidma_info = {
-    .name = "xilinx,axidma",
-    .size = sizeof(struct XilinxAXIDMA),
-    .props = axidma_properties,
-    .class_init = axidma_class_init,
+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 c7dbe00..1ce2db4 100644
--- a/hw/xilinx_axienet.c
+++ b/hw/xilinx_axienet.c
@@ -881,20 +881,22 @@ static Property xilinx_enet_properties[] = {
 
 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 DeviceInfo xilinx_enet_info = {
-    .name = "xilinx,axienet",
-    .size = sizeof(struct XilinxAXIEnet),
-    .props = xilinx_enet_properties,
-    .class_init = xilinx_enet_class_init,
+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 dc7c0c8..499feef 100644
--- a/hw/xilinx_ethlite.c
+++ b/hw/xilinx_ethlite.c
@@ -235,21 +235,23 @@ static Property xilinx_ethlite_properties[] = {
 
 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 DeviceInfo xilinx_ethlite_info = {
-    .name = "xilinx,ethlite",
-    .size = sizeof(struct xlx_ethlite),
-    .props = xilinx_ethlite_properties,
-    .class_init = xilinx_ethlite_class_init,
+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 c26b4ea..73eed6d 100644
--- a/hw/xilinx_intc.c
+++ b/hw/xilinx_intc.c
@@ -168,21 +168,23 @@ static Property xilinx_intc_properties[] = {
 
 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 DeviceInfo xilinx_intc_info = {
-    .name = "xilinx,intc",
-    .size = sizeof(struct xlx_pic),
-    .props = xilinx_intc_properties,
-    .class_init = xilinx_intc_class_init,
+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 0755e1b..c8236d2 100644
--- a/hw/xilinx_timer.c
+++ b/hw/xilinx_timer.c
@@ -227,21 +227,23 @@ static Property xilinx_timer_properties[] = {
 
 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 DeviceInfo xilinx_timer_info = {
-    .name = "xilinx,timer",
-    .size = sizeof(struct timerblock),
-    .props = xilinx_timer_properties,
-    .class_init = xilinx_timer_class_init,
+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 8baabc7..1491bba 100644
--- a/hw/xilinx_uartlite.c
+++ b/hw/xilinx_uartlite.c
@@ -218,15 +218,16 @@ static void xilinx_uartlite_class_init(ObjectClass *klass, void *data)
     sdc->init = xilinx_uartlite_init;
 }
 
-static DeviceInfo xilinx_uartlite_info = {
-    .name = "xilinx,uartlite",
-    .size = sizeof (struct xlx_uartlite),
-    .class_init = xilinx_uartlite_class_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_qdev_register(&xilinx_uartlite_info);
+    type_register_static(&xilinx_uartlite_info);
 }
 
 device_init(xilinx_uart_register)
diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c
index 6d625cb..07e4fc1 100644
--- a/hw/xio3130_downstream.c
+++ b/hw/xio3130_downstream.c
@@ -179,6 +179,7 @@ static Property xio3130_downstream_properties[] = {
 
 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;
@@ -189,21 +190,22 @@ static void xio3130_downstream_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo xio3130_downstream_info = {
-    .name = "xio3130-downstream",
-    .desc = "TI X3130 Downstream Port of PCI Express Switch",
-    .size = sizeof(PCIESlot),
-    .reset = xio3130_downstream_reset,
-    .vmsd = &vmstate_xio3130_downstream,
-    .props = xio3130_downstream_properties,
-    .class_init = xio3130_downstream_class_init,
+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 ec4c5e3..7887c92 100644
--- a/hw/xio3130_upstream.c
+++ b/hw/xio3130_upstream.c
@@ -153,6 +153,7 @@ static Property xio3130_upstream_properties[] = {
 
 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;
@@ -163,21 +164,22 @@ static void xio3130_upstream_class_init(ObjectClass *klass, void *data)
     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 DeviceInfo xio3130_upstream_info = {
-    .name = "x3130-upstream",
-    .desc = "TI X3130 Upstream Port of PCI Express Switch",
-    .size = sizeof(PCIEPort),
-    .reset = xio3130_upstream_reset,
-    .vmsd = &vmstate_xio3130_upstream,
-    .props = xio3130_upstream_properties,
-    .class_init = xio3130_upstream_class_init,
+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 b12f974..654ac55 100644
--- a/hw/z2.c
+++ b/hw/z2.c
@@ -176,17 +176,19 @@ static VMStateDescription vmstate_zipit_lcd_state = {
 
 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 DeviceInfo zipit_lcd_info = {
-    .name = "zipit-lcd",
-    .size = sizeof(ZipitLCD),
-    .vmsd = &vmstate_zipit_lcd_state,
-    .class_init = zipit_lcd_class_init,
+static TypeInfo zipit_lcd_info = {
+    .name          = "zipit-lcd",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(ZipitLCD),
+    .class_init    = zipit_lcd_class_init,
 };
 
 typedef struct {
@@ -275,19 +277,21 @@ static VMStateDescription vmstate_aer915_state = {
 
 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 DeviceInfo aer915_info = {
-    .name = "aer915",
-    .size = sizeof(AER915State),
-    .vmsd = &vmstate_aer915_state,
-    .class_init = aer915_class_init,
+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,
@@ -340,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 b14240c..055df9b 100644
--- a/hw/zaurus.c
+++ b/hw/zaurus.c
@@ -227,23 +227,25 @@ static Property scoop_sysbus_properties[] = {
 
 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 DeviceInfo scoop_sysbus_info = {
-    .name = "scoop",
-    .desc = "Scoop2 Sharp custom ASIC",
-    .size = sizeof(ScoopInfo),
-    .vmsd = &vmstate_scoop_regs,
-    .props = scoop_sysbus_properties,
-    .class_init = scoop_sysbus_class_init,
+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);
 
diff --git a/include/qemu/object.h b/include/qemu/object.h
index adbcfb1..a20271f 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -396,6 +396,8 @@ const char *object_get_typename(Object *obj);
  */
 Type type_register_static(const TypeInfo *info);
 
+#define type_register_static_alias(info, name) do { } while (0)
+
 /**
  * type_register:
  * @info: The #TypeInfo of the new type
diff --git a/usb-linux.c b/usb-linux.c
index a337db5..e7fc9ec 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -1402,8 +1402,19 @@ static const VMStateDescription vmstate_usb_host = {
     .unmigratable = 1,
 };
 
+static Property usb_host_dev_properties[] = {
+    DEFINE_PROP_UINT32("hostbus",  USBHostDevice, match.bus_num,    0),
+    DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr,       0),
+    DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
+    DEFINE_PROP_HEX32("vendorid",  USBHostDevice, match.vendor_id,  0),
+    DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
+    DEFINE_PROP_UINT32("isobufs",  USBHostDevice, iso_urb_count,    4),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
 static void usb_host_class_initfn(ObjectClass *klass, void *data)
 {
+    DeviceClass *dc = DEVICE_CLASS(klass);
     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
 
     uc->init           = usb_host_initfn;
@@ -1414,27 +1425,20 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data)
     uc->handle_control = usb_host_handle_control;
     uc->handle_reset   = usb_host_handle_reset;
     uc->handle_destroy = usb_host_handle_destroy;
+    dc->vmsd = &vmstate_usb_host;
+    dc->props = usb_host_dev_properties;
 }
 
-static struct DeviceInfo usb_host_dev_info = {
-    .name      = "usb-host",
-    .size      = sizeof(USBHostDevice),
-    .vmsd      = &vmstate_usb_host,
-    .class_init= usb_host_class_initfn,
-    .props     = (Property[]) {
-        DEFINE_PROP_UINT32("hostbus",  USBHostDevice, match.bus_num,    0),
-        DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr,       0),
-        DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
-        DEFINE_PROP_HEX32("vendorid",  USBHostDevice, match.vendor_id,  0),
-        DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
-        DEFINE_PROP_UINT32("isobufs",  USBHostDevice, iso_urb_count,    4),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static TypeInfo usb_host_dev_info = {
+    .name          = "usb-host",
+    .parent        = TYPE_USB_DEVICE,
+    .instance_size = sizeof(USBHostDevice),
+    .class_init    = usb_host_class_initfn,
 };
 
 static void usb_host_register_devices(void)
 {
-    usb_qdev_register(&usb_host_dev_info);
+    type_register_static(&usb_host_dev_info);
     usb_legacy_register("usb-host", "host", usb_host_device_open);
 }
 device_init(usb_host_register_devices)
commit 212ad111683a5b5a79a74d6141a4b75f532a4c8f
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 1 09:34:28 2012 -0600

    qdev: kill off DeviceInfo list
    
    Teach the various bits of code that need to walk through available devices to
    do so via QOM.
    
    Signed-off-by: Anthony Liguori

diff --git a/hw/qdev.c b/hw/qdev.c
index bba84e2..a30a1c2 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -38,8 +38,6 @@ 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);
@@ -125,7 +123,6 @@ static void qdev_do_register_subclass(DeviceInfo *info, const char *parent,
     TypeInfo type_info = {};
 
     assert(info->size >= sizeof(DeviceState));
-    assert(!info->next);
 
     type_info.name = name;
     type_info.parent = parent;
@@ -142,40 +139,11 @@ void qdev_register_subclass(DeviceInfo *info, const char *parent)
     if (info->alias) {
         qdev_do_register_subclass(info, parent, info->alias);
     }
-    info->next = device_info_list;
-    device_info_list = info;
-}
-
-void qdev_register(DeviceInfo *info)
-{
-    qdev_register_subclass(info, TYPE_DEVICE);
-}
-
-static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
-{
-    DeviceInfo *info;
-
-    /* first check device names */
-    for (info = device_info_list; info != NULL; info = info->next) {
-        if (strcmp(info->name, name) != 0)
-            continue;
-        return info;
-    }
-
-    /* failing that check the aliases */
-    for (info = device_info_list; info != NULL; info = info->next) {
-        if (!info->alias)
-            continue;
-        if (strcmp(info->alias, name) != 0)
-            continue;
-        return info;
-    }
-    return NULL;
 }
 
 bool qdev_exists(const char *name)
 {
-    return !!qdev_find_info(NULL, name);
+    return !!object_class_by_name(name);
 }
 
 static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
@@ -245,17 +213,28 @@ DeviceState *qdev_try_create(BusState *bus, const char *name)
     return qdev_create_from_info(bus, name);
 }
 
-static void qdev_print_devinfo(DeviceInfo *info)
+static void qdev_print_devinfo(ObjectClass *klass, void *opaque)
 {
-    error_printf("name \"%s\", bus %s",
-                 info->name, info->bus_info->name);
-    if (info->alias) {
-        error_printf(", alias \"%s\"", info->alias);
+    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;
     }
-    if (info->desc) {
-        error_printf(", desc \"%s\"", info->desc);
+
+    error_printf("name \"%s\"", object_class_get_name(klass));
+    if (dc->bus_info) {
+        error_printf(", bus %s", dc->bus_info->name);
     }
-    if (info->no_user) {
+    if (dc->alias) {
+        error_printf(", alias \"%s\"", dc->alias);
+    }
+    if (dc->desc) {
+        error_printf(", desc \"%s\"", dc->desc);
+    }
+    if (dc->no_user) {
         error_printf(", no-user");
     }
     error_printf("\n");
@@ -279,17 +258,14 @@ static int set_property(const char *name, const char *value, void *opaque)
 int qdev_device_help(QemuOpts *opts)
 {
     const char *driver;
-    DeviceInfo *info;
     Property *prop;
+    ObjectClass *klass;
+    DeviceClass *info;
 
     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);
-        }
+        bool show_no_user = false;
+        object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, &show_no_user);
         return 1;
     }
 
@@ -297,10 +273,11 @@ int qdev_device_help(QemuOpts *opts)
         return 0;
     }
 
-    info = qdev_find_info(NULL, driver);
-    if (!info) {
+    klass = object_class_by_name(driver);
+    if (!klass) {
         return 0;
     }
+    info = DEVICE_CLASS(klass);
 
     for (prop = info->props; prop && prop->name; prop++) {
         /*
@@ -312,14 +289,14 @@ int qdev_device_help(QemuOpts *opts)
         if (!prop->info->parse) {
             continue;           /* no way to set it, don't show */
         }
-        error_printf("%s.%s=%s\n", info->name, prop->name,
+        error_printf("%s.%s=%s\n", driver, 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,
+        error_printf("%s.%s=%s\n", driver, prop->name,
                      prop->info->legacy_name ?: prop->info->name);
     }
     return 1;
@@ -1085,11 +1062,7 @@ void do_info_qtree(Monitor *mon)
 
 void do_info_qdm(Monitor *mon)
 {
-    DeviceInfo *info;
-
-    for (info = device_info_list; info != NULL; info = info->next) {
-        qdev_print_devinfo(info);
-    }
+    object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, NULL);
 }
 
 int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
diff --git a/hw/qdev.h b/hw/qdev.h
index b46d06e..af167be 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -258,9 +258,7 @@ struct DeviceInfo {
     qdev_event unplug;
     qdev_event exit;
     BusInfo *bus_info;
-    struct DeviceInfo *next;
 };
-extern DeviceInfo *device_info_list;
 
 void qdev_register(DeviceInfo *info);
 void qdev_register_subclass(DeviceInfo *info, const char *parent);
diff --git a/hw/ssi.c b/hw/ssi.c
index 99a0616..994c922 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -41,7 +41,7 @@ void ssi_register_slave(DeviceInfo *info)
     assert(info->size >= sizeof(SSISlave));
     info->init = ssi_slave_init;
     info->bus_info = &ssi_bus_info;
-    qdev_register(info);
+    qdev_register_subclass(info, TYPE_SSI_SLAVE);
 }
 
 DeviceState *ssi_create_slave(SSIBus *bus, const char *name)
commit 93c511a1adad281492f18b13e164ae4ac790c052
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Dec 22 14:11:53 2011 -0600

    qom: allow object_class_foreach to take additional parameters to refine search
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/include/qemu/object.h b/include/qemu/object.h
index ba37850..adbcfb1 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -431,6 +431,7 @@ const char *object_class_get_name(ObjectClass *klass);
 ObjectClass *object_class_by_name(const char *typename);
 
 void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
+                          const char *implements_type, bool include_abstract,
                           void *opaque);
 
 #endif
diff --git a/qom/object.c b/qom/object.c
index a12895f..3dabb1a 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -467,6 +467,8 @@ ObjectClass *object_class_by_name(const char *typename)
 typedef struct OCFData
 {
     void (*fn)(ObjectClass *klass, void *opaque);
+    const char *implements_type;
+    bool include_abstract;
     void *opaque;
 } OCFData;
 
@@ -475,16 +477,28 @@ static void object_class_foreach_tramp(gpointer key, gpointer value,
 {
     OCFData *data = opaque;
     TypeImpl *type = value;
+    ObjectClass *k;
 
     type_class_init(type);
+    k = type->class;
 
-    data->fn(value, type->class);
+    if (!data->include_abstract && type->abstract) {
+        return;
+    }
+
+    if (data->implements_type && 
+        !object_class_dynamic_cast(k, data->implements_type)) {
+        return;
+    }
+
+    data->fn(k, data->opaque);
 }
 
 void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
+                          const char *implements_type, bool include_abstract,
                           void *opaque)
 {
-    OCFData data = { fn, opaque };
+    OCFData data = { fn, implements_type, include_abstract, opaque };
 
     g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
 }
commit 18b6dade8c0799c48f5c5e124b8c407cd5e22e96
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 9 12:08:01 2011 -0600

    qdev: refactor device creation to allow bus_info to be set only in class
    
    As we use class_init to set class members, DeviceInfo no longer holds this
    information.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev.c b/hw/qdev.c
index c9f890c..bba84e2 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -119,21 +119,29 @@ const char *qdev_fw_name(DeviceState *dev)
     return object_get_typename(OBJECT(dev));
 }
 
-void qdev_register_subclass(DeviceInfo *info, const char *parent)
+static void qdev_do_register_subclass(DeviceInfo *info, const char *parent,
+                                      const char *name)
 {
     TypeInfo type_info = {};
 
     assert(info->size >= sizeof(DeviceState));
     assert(!info->next);
 
-    type_info.name = info->name;
+    type_info.name = name;
     type_info.parent = parent;
     type_info.instance_size = info->size;
     type_info.class_init = qdev_subclass_init;
     type_info.class_data = info;
 
     type_register_static(&type_info);
+}
 
+void qdev_register_subclass(DeviceInfo *info, const char *parent)
+{
+    qdev_do_register_subclass(info, parent, info->name);
+    if (info->alias) {
+        qdev_do_register_subclass(info, parent, info->alias);
+    }
     info->next = device_info_list;
     device_info_list = info;
 }
@@ -173,12 +181,12 @@ bool qdev_exists(const char *name)
 static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
                                      Error **errp);
 
-static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
+static DeviceState *qdev_create_from_info(BusState *bus, const char *typename)
 {
     DeviceState *dev;
     Property *prop;
 
-    dev = DEVICE(object_new(info->name));
+    dev = DEVICE(object_new(typename));
     dev->parent_bus = bus;
     qdev_prop_set_defaults(dev, qdev_get_props(dev));
     qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
@@ -230,18 +238,11 @@ 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();
     }
 
-    info = qdev_find_info(bus->info, name);
-    if (!info) {
-        return NULL;
-    }
-
-    return qdev_create_from_info(bus, info);
+    return qdev_create_from_info(bus, name);
 }
 
 static void qdev_print_devinfo(DeviceInfo *info)
@@ -352,8 +353,8 @@ static DeviceState *qdev_get_peripheral_anon(void)
 
 DeviceState *qdev_device_add(QemuOpts *opts)
 {
+    DeviceClass *k;
     const char *driver, *path, *id;
-    DeviceInfo *info;
     DeviceState *qdev;
     BusState *bus;
 
@@ -364,12 +365,7 @@ DeviceState *qdev_device_add(QemuOpts *opts)
     }
 
     /* 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;
-    }
+    k = DEVICE_CLASS(object_class_by_name(driver));
 
     /* find bus */
     path = qemu_opt_get(opts, "bus");
@@ -378,16 +374,16 @@ DeviceState *qdev_device_add(QemuOpts *opts)
         if (!bus) {
             return NULL;
         }
-        if (bus->info != info->bus_info) {
+        if (bus->info != k->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);
+        bus = qbus_find_recursive(main_system_bus, NULL, k->bus_info);
         if (!bus) {
             qerror_report(QERR_NO_BUS_FOR_DEVICE,
-                           info->name, info->bus_info->name);
+                          driver, k->bus_info->name);
             return NULL;
         }
     }
@@ -397,7 +393,7 @@ DeviceState *qdev_device_add(QemuOpts *opts)
     }
 
     /* create device, set properties */
-    qdev = qdev_create_from_info(bus, info);
+    qdev = qdev_create_from_info(bus, driver);
     id = qemu_opts_id(opts);
     if (id) {
         qdev->id = id;
commit d253e0961965262d30843b7a0eefa687d5cbc85d
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 9 11:22:58 2011 -0600

    qdev: allow classes to overload qdev functions
    
    This allows us to drop per-Device registration functions by allowing the
    class_init functions to overload qdev methods.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev.c b/hw/qdev.c
index b273cd2..c9f890c 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -50,21 +50,39 @@ static void qdev_subclass_init(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
     DeviceInfo *info = data;
 
-    dc->fw_name = info->fw_name;
-    dc->alias = info->alias;
-    dc->desc = info->desc;
-    dc->props = info->props;
-    dc->no_user = info->no_user;
-
-    dc->reset = info->reset;
-
-    dc->vmsd = info->vmsd;
-
-    dc->init = info->init;
-    dc->unplug = info->unplug;
-    dc->exit = info->exit;
-    dc->bus_info = info->bus_info;
-
+    if (info->fw_name) {
+        dc->fw_name = info->fw_name;
+    }
+    if (info->alias) {
+        dc->alias = info->alias;
+    }
+    if (info->desc) {
+        dc->desc = info->desc;
+    }
+    if (info->props) {
+        dc->props = info->props;
+    }
+    if (info->no_user) {
+        dc->no_user = info->no_user;
+    }
+    if (info->reset) {
+        dc->reset = info->reset;
+    }
+    if (info->vmsd) {
+        dc->vmsd = info->vmsd;
+    }
+    if (info->init) {
+        dc->init = info->init;
+    }
+    if (info->unplug) {
+        dc->unplug = info->unplug;
+    }
+    if (info->exit) {
+        dc->exit = info->exit;
+    }
+    if (info->bus_info) {
+        dc->bus_info = info->bus_info;
+    }
     if (info->class_init) {
         info->class_init(klass, data);
     }
@@ -131,8 +149,6 @@ static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
 
     /* 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;
@@ -140,8 +156,6 @@ static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
 
     /* 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)
@@ -164,7 +178,6 @@ static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
     DeviceState *dev;
     Property *prop;
 
-    assert(bus->info == info->bus_info);
     dev = DEVICE(object_new(info->name));
     dev->parent_bus = bus;
     qdev_prop_set_defaults(dev, qdev_get_props(dev));
commit 6e008585eb0a771e5011602e1bf2bf299b64457d
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 9 11:06:57 2011 -0600

    qdev: remove info from class
    
    Now DeviceInfo is no longer used after object construction.  All of the
    relevant members have been moved to DeviceClass.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/pci.c b/hw/pci.c
index 235ea00..43dc1fb 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1467,7 +1467,9 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
     }
 
     bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
-    pci_dev = do_pci_register_device(pci_dev, bus, base->name, pci_dev->devfn);
+    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 && pc->no_hotplug) {
diff --git a/hw/qdev.c b/hw/qdev.c
index 18c5876..b273cd2 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -48,46 +48,54 @@ static BusState *qbus_find(const char *path);
 static void qdev_subclass_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
+    DeviceInfo *info = data;
 
-    dc->info = data;
-    dc->reset = dc->info->reset;
+    dc->fw_name = info->fw_name;
+    dc->alias = info->alias;
+    dc->desc = info->desc;
+    dc->props = info->props;
+    dc->no_user = info->no_user;
 
-    /* Poison to try to detect future uses */
-    dc->info->reset = NULL;
+    dc->reset = info->reset;
 
-    if (dc->info->class_init) {
-        dc->info->class_init(klass, data);
-    }
-}
+    dc->vmsd = info->vmsd;
 
-static DeviceInfo *qdev_get_info(DeviceState *dev)
-{
-    return DEVICE_GET_CLASS(dev)->info;
+    dc->init = info->init;
+    dc->unplug = info->unplug;
+    dc->exit = info->exit;
+    dc->bus_info = info->bus_info;
+
+    if (info->class_init) {
+        info->class_init(klass, data);
+    }
 }
 
 const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
 {
-    return qdev_get_info(dev)->vmsd;
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
+    return dc->vmsd;
 }
 
 BusInfo *qdev_get_bus_info(DeviceState *dev)
 {
-    return qdev_get_info(dev)->bus_info;
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
+    return dc->bus_info;
 }
 
 Property *qdev_get_props(DeviceState *dev)
 {
-    return qdev_get_info(dev)->props;
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
+    return dc->props;
 }
 
 const char *qdev_fw_name(DeviceState *dev)
 {
-    DeviceInfo *info = qdev_get_info(dev);
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
 
-    if (info->fw_name) {
-        return info->fw_name;
-    } else if (info->alias) {
-        return info->alias;
+    if (dc->fw_name) {
+        return dc->fw_name;
+    } else if (dc->alias) {
+        return dc->alias;
     }
 
     return object_get_typename(OBJECT(dev));
@@ -159,7 +167,7 @@ static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
     assert(bus->info == info->bus_info);
     dev = DEVICE(object_new(info->name));
     dev->parent_bus = bus;
-    qdev_prop_set_defaults(dev, qdev_get_info(dev)->props);
+    qdev_prop_set_defaults(dev, qdev_get_props(dev));
     qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
     qdev_prop_set_globals(dev);
     QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
@@ -172,12 +180,12 @@ static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
     QTAILQ_INIT(&dev->properties);
     dev->state = DEV_STATE_CREATED;
 
-    for (prop = qdev_get_info(dev)->props; prop && prop->name; prop++) {
+    for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
         qdev_property_add_legacy(dev, prop, NULL);
         qdev_property_add_static(dev, prop, NULL);
     }
 
-    for (prop = qdev_get_info(dev)->bus_info->props; prop && prop->name; prop++) {
+    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);
     }
@@ -407,16 +415,19 @@ 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 = qdev_get_info(dev)->init(dev, qdev_get_info(dev));
+
+    /* FIXME hopefully this doesn't break anything */
+    rc = dc->init(dev, NULL);
     if (rc < 0) {
         qdev_free(dev);
         return rc;
     }
-    if (qdev_get_info(dev)->vmsd) {
-        vmstate_register_with_alias_id(dev, -1, qdev_get_info(dev)->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);
     }
@@ -437,15 +448,17 @@ 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(qdev_get_info(dev)->unplug != NULL);
+    assert(dc->unplug != NULL);
 
     qdev_hot_removed = true;
 
-    return qdev_get_info(dev)->unplug(dev);
+    return dc->unplug(dev);
 }
 
 static int qdev_reset_one(DeviceState *dev, void *opaque)
@@ -500,10 +513,9 @@ int qdev_simple_unplug_cb(DeviceState *dev)
    way is somewhat unclean, and best avoided.  */
 void qdev_init_nofail(DeviceState *dev)
 {
-    DeviceInfo *info = qdev_get_info(dev);
-
     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);
     }
 }
@@ -553,6 +565,7 @@ void qdev_free(DeviceState *dev)
 {
     BusState *bus;
     Property *prop;
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
 
     qdev_property_del_all(dev);
 
@@ -561,15 +574,18 @@ void qdev_free(DeviceState *dev)
             bus = QLIST_FIRST(&dev->child_bus);
             qbus_free(bus);
         }
-        if (qdev_get_info(dev)->vmsd)
-            vmstate_unregister(dev, qdev_get_info(dev)->vmsd, dev);
-        if (qdev_get_info(dev)->exit)
-            qdev_get_info(dev)->exit(dev);
-        if (dev->opts)
+        if (qdev_get_vmsd(dev)) {
+            vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
+        }
+        if (dc->exit) {
+            dc->exit(dev);
+        }
+        if (dev->opts) {
             qemu_opts_del(dev->opts);
+        }
     }
     QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
-    for (prop = qdev_get_info(dev)->props; prop && prop->name; prop++) {
+    for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
         if (prop->info->free) {
             prop->info->free(dev, prop);
         }
@@ -817,7 +833,9 @@ static DeviceState *qbus_find_dev(BusState *bus, char *elem)
         }
     }
     QTAILQ_FOREACH(dev, &bus->children, sibling) {
-        if (qdev_get_info(dev)->alias && strcmp(qdev_get_info(dev)->alias, elem) == 0) {
+        DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
+        if (dc->alias && strcmp(dc->alias, elem) == 0) {
             return dev;
         }
     }
@@ -1028,7 +1046,7 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
     if (dev->num_gpio_out) {
         qdev_printf("gpio-out %d\n", dev->num_gpio_out);
     }
-    qdev_print_props(mon, dev, qdev_get_info(dev)->props, "dev", indent);
+    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);
diff --git a/hw/qdev.h b/hw/qdev.h
index 5476756..b46d06e 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -72,10 +72,30 @@ typedef struct DeviceProperty
 #define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE)
 #define DEVICE_GET_CLASS(obj) OBJECT_GET_CLASS(DeviceClass, (obj), TYPE_DEVICE)
 
+typedef int (*qdev_initfn)(DeviceState *dev, DeviceInfo *info);
+typedef int (*qdev_event)(DeviceState *dev);
+typedef void (*qdev_resetfn)(DeviceState *dev);
+
 typedef struct DeviceClass {
     ObjectClass parent_class;
-    DeviceInfo *info;
+
+    const char *fw_name;
+    const char *alias;
+    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
@@ -213,10 +233,6 @@ 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;
commit 4be9f0d11cf2dbb1eb3f55b33c87d6df3aa7d578
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 9 10:51:49 2011 -0600

    qdev: make DeviceInfo private
    
    Introduce accessors and remove any code that directly accesses DeviceInfo
    members.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/pci.c b/hw/pci.c
index 6a0b1f5..235ea00 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1673,6 +1673,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;
@@ -1709,10 +1710,13 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
         size = 1 << qemu_fls(size);
     }
 
-    if (qdev_get_info(&pdev->qdev)->vmsd)
-        snprintf(name, sizeof(name), "%s.rom", qdev_get_info(&pdev->qdev)->vmsd->name);
-    else
+    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);
@@ -1953,8 +1957,7 @@ static int pci_qdev_find_recursive(PCIBus *bus,
     }
 
     /* roughly check if given qdev is pci device */
-    if (qdev_get_info(qdev)->init == &pci_qdev_init &&
-        qdev->parent_bus->info == &pci_bus_info) {
+    if (object_dynamic_cast(OBJECT(qdev), TYPE_PCI_DEVICE)) {
         *pdev = PCI_DEVICE(qdev);
         return 0;
     }
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 028bee7..2e3ef70 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -1015,7 +1015,7 @@ static Property *qdev_prop_find(DeviceState *dev, const char *name)
     Property *prop;
 
     /* device properties */
-    prop = qdev_prop_walk(qdev_get_info(dev)->props, name);
+    prop = qdev_prop_walk(qdev_get_props(dev), name);
     if (prop)
         return prop;
 
@@ -1221,7 +1221,7 @@ void qdev_prop_set_globals(DeviceState *dev)
 
     QTAILQ_FOREACH(prop, &global_props, next) {
         if (strcmp(object_get_typename(OBJECT(dev)), prop->driver) != 0 &&
-            strcmp(qdev_get_info(dev)->bus_info->name, 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 a8c24de..18c5876 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -60,11 +60,39 @@ static void qdev_subclass_init(ObjectClass *klass, void *data)
     }
 }
 
-DeviceInfo *qdev_get_info(DeviceState *dev)
+static DeviceInfo *qdev_get_info(DeviceState *dev)
 {
     return DEVICE_GET_CLASS(dev)->info;
 }
 
+const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
+{
+    return qdev_get_info(dev)->vmsd;
+}
+
+BusInfo *qdev_get_bus_info(DeviceState *dev)
+{
+    return qdev_get_info(dev)->bus_info;
+}
+
+Property *qdev_get_props(DeviceState *dev)
+{
+    return qdev_get_info(dev)->props;
+}
+
+const char *qdev_fw_name(DeviceState *dev)
+{
+    DeviceInfo *info = qdev_get_info(dev);
+
+    if (info->fw_name) {
+        return info->fw_name;
+    } else if (info->alias) {
+        return info->alias;
+    }
+
+    return object_get_typename(OBJECT(dev));
+}
+
 void qdev_register_subclass(DeviceInfo *info, const char *parent)
 {
     TypeInfo type_info = {};
diff --git a/hw/qdev.h b/hw/qdev.h
index 364e91d..5476756 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -405,22 +405,8 @@ 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);
 
-DeviceInfo *qdev_get_info(DeviceState *dev);
-
-static inline const char *qdev_fw_name(DeviceState *dev)
-{
-    DeviceInfo *info = qdev_get_info(dev);
-
-    if (info->fw_name) {
-        return info->fw_name;
-    } else if (info->alias) {
-        return info->alias;
-    }
-
-    return object_get_typename(OBJECT(dev));
-}
-
 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;
 
@@ -668,4 +654,12 @@ void qdev_machine_init(void);
  */
 void device_reset(DeviceState *dev);
 
+const VMStateDescription *qdev_get_vmsd(DeviceState *dev);
+
+const char *qdev_fw_name(DeviceState *dev);
+
+BusInfo *qdev_get_bus_info(DeviceState *dev);
+
+Property *qdev_get_props(DeviceState *dev);
+
 #endif
commit ba02430f1a681173cff5336c626d6edc5ea268db
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Dec 8 14:56:53 2011 -0600

    usb: separate out legacy usb registration from type registration
    
    Type registeration is going to get turned into a QOM call so decouple the
    legacy support.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/usb-audio.c b/hw/usb-audio.c
index 561ae31..459f162 100644
--- a/hw/usb-audio.c
+++ b/hw/usb-audio.c
@@ -704,7 +704,8 @@ static struct DeviceInfo usb_audio_info = {
 
 static void usb_audio_register_devices(void)
 {
-    usb_qdev_register(&usb_audio_info, "audio", NULL);
+    usb_qdev_register(&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 bf8c470..f497a44 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -550,6 +550,6 @@ static struct DeviceInfo bt_info = {
 
 static void usb_bt_register_devices(void)
 {
-    usb_qdev_register(&bt_info, NULL, NULL);
+    usb_qdev_register(&bt_info);
 }
 device_init(usb_bt_register_devices)
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index aeef908..6b0adfd 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -208,25 +208,27 @@ typedef struct LegacyUSBFactory
 
 static GSList *legacy_usb_factory;
 
-void usb_qdev_register(DeviceInfo *info,
-                       const char *usbdevice_name,
-                       USBDevice *(*usbdevice_init)(const char *params))
+void usb_legacy_register(const char *typename, const char *usbdevice_name,
+                         USBDevice *(*usbdevice_init)(const char *params))
 {
-    info->bus_info = &usb_bus_info;
-    info->init     = usb_qdev_init;
-    info->unplug   = qdev_simple_unplug_cb;
-    info->exit     = usb_qdev_exit;
-    qdev_register_subclass(info, TYPE_USB_DEVICE);
-
     if (usbdevice_name) {
         LegacyUSBFactory *f = g_malloc0(sizeof(*f));
-        f->name = info->name;
+        f->name = typename;
         f->usbdevice_name = usbdevice_name;
         f->usbdevice_init = usbdevice_init;
         legacy_usb_factory = g_slist_append(legacy_usb_factory, f);
     }
 }
 
+void usb_qdev_register(DeviceInfo *info)
+{
+    info->bus_info = &usb_bus_info;
+    info->init     = usb_qdev_init;
+    info->unplug   = qdev_simple_unplug_cb;
+    info->exit     = usb_qdev_exit;
+    qdev_register_subclass(info, TYPE_USB_DEVICE);
+}
+
 USBDevice *usb_create(USBBus *bus, const char *name)
 {
     DeviceState *dev;
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index aff81fa..a261d7d 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -1352,6 +1352,7 @@ static TypeInfo ccid_card_type_info = {
 static void ccid_register_devices(void)
 {
     type_register_static(&ccid_card_type_info);
-    usb_qdev_register(&ccid_info, "ccid", NULL);
+    usb_qdev_register(&ccid_info);
+    usb_legacy_register(CCID_DEV_NAME, "ccid", NULL);
 }
 device_init(ccid_register_devices)
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 4af27a2..669aae4 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -617,8 +617,11 @@ static struct DeviceInfo usb_keyboard_info = {
 
 static void usb_hid_register_devices(void)
 {
-    usb_qdev_register(&usb_tablet_info, "tablet", NULL);
-    usb_qdev_register(&usb_mouse_info, "mouse", NULL);
-    usb_qdev_register(&usb_keyboard_info, "keyboard", NULL);
+    usb_qdev_register(&usb_tablet_info);
+    usb_legacy_register("usb-tablet", "tablet", NULL);
+    usb_qdev_register(&usb_mouse_info);
+    usb_legacy_register("usb-mouse", "mouse", NULL);
+    usb_qdev_register(&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 ee4e6a6..3e33685 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -557,6 +557,6 @@ static struct DeviceInfo hub_info = {
 
 static void usb_hub_register_devices(void)
 {
-    usb_qdev_register(&hub_info, NULL, NULL);
+    usb_qdev_register(&hub_info);
 }
 device_init(usb_hub_register_devices)
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index ceb01e0..19d0d7b 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -667,6 +667,7 @@ static struct DeviceInfo msd_info = {
 
 static void usb_msd_register_devices(void)
 {
-    usb_qdev_register(&msd_info, "disk", usb_msd_init);
+    usb_qdev_register(&msd_info);
+    usb_legacy_register("usb-storage", "disk", usb_msd_init);
 }
 device_init(usb_msd_register_devices)
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 57b58ac..65eee95 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1413,6 +1413,7 @@ static struct DeviceInfo net_info = {
 
 static void usb_net_register_devices(void)
 {
-    usb_qdev_register(&net_info, "net", usb_net_init);
+    usb_qdev_register(&net_info);
+    usb_legacy_register("usb-net", "net", usb_net_init);
 }
 device_init(usb_net_register_devices)
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index de49607..00b4985 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -622,7 +622,9 @@ static struct DeviceInfo braille_info = {
 
 static void usb_serial_register_devices(void)
 {
-    usb_qdev_register(&serial_info, "serial", usb_serial_init);
-    usb_qdev_register(&braille_info, "braille", usb_braille_init);
+    usb_qdev_register(&serial_info);
+    usb_legacy_register("usb-serial", "serial", usb_serial_init);
+    usb_qdev_register(&braille_info);
+    usb_legacy_register("usb-braille", "braille", usb_braille_init);
 }
 device_init(usb_serial_register_devices)
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 9b20a31..40bb199 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -373,6 +373,7 @@ static struct DeviceInfo wacom_info = {
 
 static void usb_wacom_register_devices(void)
 {
-    usb_qdev_register(&wacom_info, "wacom-tablet", NULL);
+    usb_qdev_register(&wacom_info);
+    usb_legacy_register("usb-wacom-tablet", "wacom-tablet", NULL);
 }
 device_init(usb_wacom_register_devices)
diff --git a/hw/usb.h b/hw/usb.h
index 5b9badb..b9b6742 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -418,9 +418,9 @@ struct USBBusOps {
 
 void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
 USBBus *usb_bus_find(int busnr);
-void usb_qdev_register(DeviceInfo *info,
-                       const char *usbdevice_name,
-                       USBDevice *(*usbdevice_init)(const char *params));
+void usb_qdev_register(DeviceInfo *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);
diff --git a/usb-linux.c b/usb-linux.c
index 31810f6..a337db5 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -1434,7 +1434,8 @@ static struct DeviceInfo usb_host_dev_info = {
 
 static void usb_host_register_devices(void)
 {
-    usb_qdev_register(&usb_host_dev_info, "host", usb_host_device_open);
+    usb_qdev_register(&usb_host_dev_info);
+    usb_legacy_register("usb-host", "host", usb_host_device_open);
 }
 device_init(usb_host_register_devices)
 
commit 7f595609b49615b07c50b7182c4ef125c39cb5da
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Sun Dec 4 16:13:14 2011 -0600

    usb-hid: simplify class initialization a bit
    
    We can probably model USBHidDevice as a base class to get even better code
    sharing but for now, just use a common function to initialize the common class
    members.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 88fdd35..4af27a2 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -553,13 +553,10 @@ static const VMStateDescription vmstate_usb_kbd = {
     }
 };
 
-static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
+static void usb_hid_class_initfn(ObjectClass *klass, void *data)
 {
     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
 
-    uc->init           = usb_tablet_initfn;
-    uc->product_desc   = "QEMU USB Tablet";
-    uc->usb_desc       = &desc_tablet;
     uc->handle_packet  = usb_generic_handle_packet;
     uc->handle_reset   = usb_hid_handle_reset;
     uc->handle_control = usb_hid_handle_control;
@@ -567,6 +564,16 @@ static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
     uc->handle_destroy = usb_hid_handle_destroy;
 }
 
+static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
+{
+    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;
+}
+
 static struct DeviceInfo usb_tablet_info = {
     .name      = "usb-tablet",
     .size      = sizeof(USBHIDState),
@@ -578,14 +585,10 @@ static void usb_mouse_class_initfn(ObjectClass *klass, void *data)
 {
     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;
-    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 struct DeviceInfo usb_mouse_info = {
@@ -599,14 +602,10 @@ static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
 {
     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;
-    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 struct DeviceInfo usb_keyboard_info = {
commit f78b0f05414f911d36afcd52f2330574d5a21952
Author: Andreas Färber <afaerber at suse.de>
Date:   Thu Dec 29 16:55:43 2011 +0100

    linux-user: Fix sa_flags byte swaps for mips
    
    sa_flags is uint32_t for mips{,n32,64}, so don't use tswapal().
    
    edited by Riku Voipio: likewise on alpha
    
    Reported-by: Khansa Butt <khansa at kics.edu.pk>
    Suggested-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Cc: Ehsan Ul Haq <ehsan.ulhaq at kics.edu.pk>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/signal.c b/linux-user/signal.c
index ded12ca..79a39dc 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -587,7 +587,11 @@ int do_sigaction(int sig, const struct target_sigaction *act,
 #endif
     if (oact) {
         oact->_sa_handler = tswapal(k->_sa_handler);
+#if defined(TARGET_MIPS) || defined (TARGET_ALPHA)
+        oact->sa_flags = bswap32(k->sa_flags);
+#else
         oact->sa_flags = tswapal(k->sa_flags);
+#endif
 #if !defined(TARGET_MIPS)
         oact->sa_restorer = tswapal(k->sa_restorer);
 #endif
@@ -596,7 +600,11 @@ int do_sigaction(int sig, const struct target_sigaction *act,
     if (act) {
         /* FIXME: This is not threadsafe.  */
         k->_sa_handler = tswapal(act->_sa_handler);
+#if defined(TARGET_MIPS) || defined (TARGET_ALPHA)
+        k->sa_flags = bswap32(act->sa_flags);
+#else
         k->sa_flags = tswapal(act->sa_flags);
+#endif
 #if !defined(TARGET_MIPS)
         k->sa_restorer = tswapal(act->sa_restorer);
 #endif
commit 2aeb36a897c6de08e9ede9e318d5970855b4b8f3
Author: Andreas Färber <afaerber at suse.de>
Date:   Thu Dec 29 16:55:42 2011 +0100

    linux-user: Define TARGET_QEMU_ESIGRETURN for mips64
    
    Copied from mips/syscall.h.
    
    Signed-off-by: Khansa Butt <khansa at kics.edu.pk>
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h
index 668a2b9..e436ea5 100644
--- a/linux-user/mips64/syscall.h
+++ b/linux-user/mips64/syscall.h
@@ -218,4 +218,7 @@ struct target_pt_regs {
 
 
 
+/* Nasty hack: define a fake errno value for use by sigreturn. */
+#define TARGET_QEMU_ESIGRETURN 255
+
 #define UNAME_MACHINE "mips64"
commit 63249cb9ebaf327ecc30bac90c1625debcd759cd
Author: Andreas Färber <afaerber at suse.de>
Date:   Thu Dec 29 16:55:41 2011 +0100

    linux-user: Define TARGET_QEMU_ESIGRETURN for mipsn32
    
    Copied from mips/syscall.h.
    
    Signed-off-by: Ulrich Hecht <uli at suse.de>
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/mipsn32/syscall.h b/linux-user/mipsn32/syscall.h
index 4ec506c..ebe98f2 100644
--- a/linux-user/mipsn32/syscall.h
+++ b/linux-user/mipsn32/syscall.h
@@ -218,4 +218,7 @@ struct target_pt_regs {
 
 
 
+/* Nasty hack: define a fake errno value for use by sigreturn. */
+#define TARGET_QEMU_ESIGRETURN 255
+
 #define UNAME_MACHINE "mips64"
commit 10ecb3f66558e3634556eb538305a06f713a39f2
Author: Andreas Färber <afaerber at suse.de>
Date:   Thu Dec 29 16:55:40 2011 +0100

    linux-user: Add default configs for mips64[el]
    
    Prepares for mips64[el]-linux-user targets.
    
    Signed-off-by: Khansa Butt <khansa at kics.edu.pk>
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/default-configs/mips64-linux-user.mak b/default-configs/mips64-linux-user.mak
new file mode 100644
index 0000000..1598bfc
--- /dev/null
+++ b/default-configs/mips64-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for mips64-linux-user
diff --git a/default-configs/mips64el-linux-user.mak b/default-configs/mips64el-linux-user.mak
new file mode 100644
index 0000000..629f084
--- /dev/null
+++ b/default-configs/mips64el-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for mips64el-linux-user
commit 72f341ff7a4aefef03a2b450d12f3278a7c7b552
Author: Andreas Färber <afaerber at suse.de>
Date:   Thu Dec 29 16:55:39 2011 +0100

    linux-user: Add default-configs for mipsn32[el]
    
    Prepares for mipsn32[el]-linux-user targets.
    
    Signed-off-by: Ulricht Hecht <uli at suse.de>
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/default-configs/mipsn32-linux-user.mak b/default-configs/mipsn32-linux-user.mak
new file mode 100644
index 0000000..5b97919
--- /dev/null
+++ b/default-configs/mipsn32-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for mipsn32-linux-user
diff --git a/default-configs/mipsn32el-linux-user.mak b/default-configs/mipsn32el-linux-user.mak
new file mode 100644
index 0000000..d6367ff
--- /dev/null
+++ b/default-configs/mipsn32el-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for mipsn32el-linux-user
commit fb5590f7f5a897fc8e2ff36051fa0aa917ef4053
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Dec 14 15:37:19 2011 +0000

    linux-user: Implement *listxattr syscalls
    
    Implement listxattr, flistxattr and llistxattr syscalls.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 762115b..ee8899e 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -7798,9 +7798,43 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #ifdef TARGET_NR_setxattr
     case TARGET_NR_listxattr:
     case TARGET_NR_llistxattr:
+    {
+        void *p, *b = 0;
+        if (arg2) {
+            b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+            if (!b) {
+                ret = -TARGET_EFAULT;
+                break;
+            }
+        }
+        p = lock_user_string(arg1);
+        if (p) {
+            if (num == TARGET_NR_listxattr) {
+                ret = get_errno(listxattr(p, b, arg3));
+            } else {
+                ret = get_errno(llistxattr(p, b, arg3));
+            }
+        } else {
+            ret = -TARGET_EFAULT;
+        }
+        unlock_user(p, arg1, 0);
+        unlock_user(b, arg2, arg3);
+        break;
+    }
     case TARGET_NR_flistxattr:
-        ret = -TARGET_EOPNOTSUPP;
+    {
+        void *b = 0;
+        if (arg2) {
+            b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+            if (!b) {
+                ret = -TARGET_EFAULT;
+                break;
+            }
+        }
+        ret = get_errno(flistxattr(arg1, b, arg3));
+        unlock_user(b, arg2, arg3);
         break;
+    }
     case TARGET_NR_setxattr:
     case TARGET_NR_lsetxattr:
         {
commit 30297b55f797e5b74d1823b64c52b1bebd2a5d85
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Dec 14 15:37:18 2011 +0000

    linux-user/syscall.c: Implement f and l versions of set/get/removexattr
    
    Implement the f and l versions (operate on fd, don't follow links)
    of the setxattr, getxattr and removexattr syscalls.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 0a78a18..762115b 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -7796,18 +7796,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #endif
 #ifdef CONFIG_ATTR
 #ifdef TARGET_NR_setxattr
-    case TARGET_NR_lsetxattr:
-    case TARGET_NR_fsetxattr:
-    case TARGET_NR_lgetxattr:
-    case TARGET_NR_fgetxattr:
     case TARGET_NR_listxattr:
     case TARGET_NR_llistxattr:
     case TARGET_NR_flistxattr:
-    case TARGET_NR_lremovexattr:
-    case TARGET_NR_fremovexattr:
         ret = -TARGET_EOPNOTSUPP;
         break;
     case TARGET_NR_setxattr:
+    case TARGET_NR_lsetxattr:
         {
             void *p, *n, *v = 0;
             if (arg3) {
@@ -7820,7 +7815,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             p = lock_user_string(arg1);
             n = lock_user_string(arg2);
             if (p && n) {
-                ret = get_errno(setxattr(p, n, v, arg4, arg5));
+                if (num == TARGET_NR_setxattr) {
+                    ret = get_errno(setxattr(p, n, v, arg4, arg5));
+                } else {
+                    ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
+                }
             } else {
                 ret = -TARGET_EFAULT;
             }
@@ -7829,7 +7828,28 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             unlock_user(v, arg3, 0);
         }
         break;
+    case TARGET_NR_fsetxattr:
+        {
+            void *n, *v = 0;
+            if (arg3) {
+                v = lock_user(VERIFY_READ, arg3, arg4, 1);
+                if (!v) {
+                    ret = -TARGET_EFAULT;
+                    break;
+                }
+            }
+            n = lock_user_string(arg2);
+            if (n) {
+                ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
+            } else {
+                ret = -TARGET_EFAULT;
+            }
+            unlock_user(n, arg2, 0);
+            unlock_user(v, arg3, 0);
+        }
+        break;
     case TARGET_NR_getxattr:
+    case TARGET_NR_lgetxattr:
         {
             void *p, *n, *v = 0;
             if (arg3) {
@@ -7842,7 +7862,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             p = lock_user_string(arg1);
             n = lock_user_string(arg2);
             if (p && n) {
-                ret = get_errno(getxattr(p, n, v, arg4));
+                if (num == TARGET_NR_getxattr) {
+                    ret = get_errno(getxattr(p, n, v, arg4));
+                } else {
+                    ret = get_errno(lgetxattr(p, n, v, arg4));
+                }
             } else {
                 ret = -TARGET_EFAULT;
             }
@@ -7851,13 +7875,38 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             unlock_user(v, arg3, arg4);
         }
         break;
+    case TARGET_NR_fgetxattr:
+        {
+            void *n, *v = 0;
+            if (arg3) {
+                v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+                if (!v) {
+                    ret = -TARGET_EFAULT;
+                    break;
+                }
+            }
+            n = lock_user_string(arg2);
+            if (n) {
+                ret = get_errno(fgetxattr(arg1, n, v, arg4));
+            } else {
+                ret = -TARGET_EFAULT;
+            }
+            unlock_user(n, arg2, 0);
+            unlock_user(v, arg3, arg4);
+        }
+        break;
     case TARGET_NR_removexattr:
+    case TARGET_NR_lremovexattr:
         {
             void *p, *n;
             p = lock_user_string(arg1);
             n = lock_user_string(arg2);
             if (p && n) {
-                ret = get_errno(removexattr(p, n));
+                if (num == TARGET_NR_removexattr) {
+                    ret = get_errno(removexattr(p, n));
+                } else {
+                    ret = get_errno(lremovexattr(p, n));
+                }
             } else {
                 ret = -TARGET_EFAULT;
             }
@@ -7865,6 +7914,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             unlock_user(n, arg2, 0);
         }
         break;
+    case TARGET_NR_fremovexattr:
+        {
+            void *n;
+            n = lock_user_string(arg2);
+            if (n) {
+                ret = get_errno(fremovexattr(arg1, n));
+            } else {
+                ret = -TARGET_EFAULT;
+            }
+            unlock_user(n, arg2, 0);
+        }
+        break;
 #endif
 #endif /* CONFIG_ATTR */
 #ifdef TARGET_NR_set_thread_area
commit e3c33ec6b07dc4d0503cb43b2114be47fc344d36
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Dec 14 15:37:17 2011 +0000

    linux-user: Allow NULL value pointer in setxattr and getxattr
    
    It's valid to pass a NULL value pointer to setxattr, so don't
    fail this case EFAULT.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 06b19e0..0a78a18 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -7809,11 +7809,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         break;
     case TARGET_NR_setxattr:
         {
-            void *p, *n, *v;
+            void *p, *n, *v = 0;
+            if (arg3) {
+                v = lock_user(VERIFY_READ, arg3, arg4, 1);
+                if (!v) {
+                    ret = -TARGET_EFAULT;
+                    break;
+                }
+            }
             p = lock_user_string(arg1);
             n = lock_user_string(arg2);
-            v = lock_user(VERIFY_READ, arg3, arg4, 1);
-            if (p && n && v) {
+            if (p && n) {
                 ret = get_errno(setxattr(p, n, v, arg4, arg5));
             } else {
                 ret = -TARGET_EFAULT;
@@ -7825,11 +7831,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         break;
     case TARGET_NR_getxattr:
         {
-            void *p, *n, *v;
+            void *p, *n, *v = 0;
+            if (arg3) {
+                v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+                if (!v) {
+                    ret = -TARGET_EFAULT;
+                    break;
+                }
+            }
             p = lock_user_string(arg1);
             n = lock_user_string(arg2);
-            v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
-            if (p && n && v) {
+            if (p && n) {
                 ret = get_errno(getxattr(p, n, v, arg4));
             } else {
                 ret = -TARGET_EFAULT;
commit 5379557b8d5acb140c17e00441fda45eae627fed
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Nov 24 00:44:43 2011 +0100

    linux-user: fix wait* syscall status returns
    
    When calling wait4 or waitpid with a status pointer and WNOHANG, the
    syscall can potentially not modify the status pointer input. Now if we
    have guest code like:
    
      int status = 0;
      waitpid(pid, &status, WNOHANG);
      if (status)
         <breakage>
    
    then we have to make sure that in case status did not change we actually
    return the guest's initialized status variable instead of our own uninitialized.
    We fail to do so today, as we proxy everything through an uninitialized status
    variable which for me ended up always containing the last error code.
    
    This patch fixes some test cases when building yast2-core in OBS for ARM.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 29d92c4..06b19e0 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -4867,7 +4867,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         {
             int status;
             ret = get_errno(waitpid(arg1, &status, arg3));
-            if (!is_error(ret) && arg2
+            if (!is_error(ret) && arg2 && ret
                 && put_user_s32(host_to_target_waitstatus(status), arg2))
                 goto efault;
         }
@@ -6423,7 +6423,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                 rusage_ptr = NULL;
             ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
             if (!is_error(ret)) {
-                if (status_ptr) {
+                if (status_ptr && ret) {
                     status = host_to_target_waitstatus(status);
                     if (put_user_s32(status, status_ptr))
                         goto efault;
commit 2a7e12455c1d388e41f4c8d2231fb48a968792cd
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Mon Nov 21 12:21:19 2011 +0000

    linux-user/strace.c: Correct errno printing for mmap etc
    
    Correct the printing of errnos for syscalls which are handled
    via print_syscall_ret_addr (mmap, mmap2, brk, shmat): errnos
    are returned as negative returned values at this level, not
    via the host 'errno' variable.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/strace.c b/linux-user/strace.c
index 269481e..05a0d3e 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1,5 +1,4 @@
 #include <stdio.h>
-#include <errno.h>
 #include <sys/ipc.h>
 #include <sys/msg.h>
 #include <sys/sem.h>
@@ -286,11 +285,11 @@ print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
 {
     char *errstr = NULL;
 
-    if (ret == -1) {
-        errstr = target_strerror(errno);
+    if (ret < 0) {
+        errstr = target_strerror(-ret);
     }
-    if ((ret == -1) && errstr) {
-        gemu_log(" = -1 errno=%d (%s)\n", errno, errstr);
+    if (errstr) {
+        gemu_log(" = -1 errno=%d (%s)\n", (int)-ret, errstr);
     } else {
         gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
     }
commit 962b289ef35087fcd8764e4e29808d8ac90157f7
Author: Alexander Graf <agraf at suse.de>
Date:   Mon Nov 21 12:04:07 2011 +0100

    linux-user: fix QEMU_STRACE=1 segfault
    
    While debugging some issues with QEMU_STRACE I stumbled over segmentation
    faults that were pretty reproducible. Turns out we tried to treat a
    normal return value as errno, resulting in an access over array boundaries
    for the resolution.
    
    Fix this by allowing failure to resolve invalid errnos into strings.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/strace.c b/linux-user/strace.c
index 90027a1..269481e 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -284,8 +284,13 @@ print_ipc(const struct syscallname *name,
 static void
 print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
 {
-if( ret == -1 ) {
-        gemu_log(" = -1 errno=%d (%s)\n", errno, target_strerror(errno));
+    char *errstr = NULL;
+
+    if (ret == -1) {
+        errstr = target_strerror(errno);
+    }
+    if ((ret == -1) && errstr) {
+        gemu_log(" = -1 errno=%d (%s)\n", errno, errstr);
     } else {
         gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
     }
@@ -1515,14 +1520,19 @@ void
 print_syscall_ret(int num, abi_long ret)
 {
     int i;
+    char *errstr = NULL;
 
     for(i=0;i<nsyscalls;i++)
         if( scnames[i].nr == num ) {
             if( scnames[i].result != NULL ) {
                 scnames[i].result(&scnames[i],ret);
             } else {
-                if( ret < 0 ) {
-                    gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret, target_strerror(-ret));
+                if (ret < 0) {
+                    errstr = target_strerror(-ret);
+                }
+                if (errstr) {
+                    gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n",
+                             -ret, errstr);
                 } else {
                     gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
                 }
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 15b8b22..29d92c4 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -731,6 +731,9 @@ static inline int is_error(abi_long ret)
 
 char *target_strerror(int err)
 {
+    if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
+        return NULL;
+    }
     return strerror(target_to_host_errno(err));
 }
 
commit 583359a68922fb91b793a5ad3a2dd4536bf9b99e
Author: Akos PASZTORY <akos.pasztory at gmail.com>
Date:   Mon Nov 14 15:09:49 2011 +0200

    linux-user: add SO_PEERCRED support for getsockopt
    
    Signed-off-by: Akos PASZTORY <akos.pasztory at gmail.com>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index c6bfcd8..15b8b22 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -1530,9 +1530,41 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
         case TARGET_SO_LINGER:
         case TARGET_SO_RCVTIMEO:
         case TARGET_SO_SNDTIMEO:
-        case TARGET_SO_PEERCRED:
         case TARGET_SO_PEERNAME:
             goto unimplemented;
+        case TARGET_SO_PEERCRED: {
+            struct ucred cr;
+            socklen_t crlen;
+            struct target_ucred *tcr;
+
+            if (get_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            if (len < 0) {
+                return -TARGET_EINVAL;
+            }
+
+            crlen = sizeof(cr);
+            ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
+                                       &cr, &crlen));
+            if (ret < 0) {
+                return ret;
+            }
+            if (len > crlen) {
+                len = crlen;
+            }
+            if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
+                return -TARGET_EFAULT;
+            }
+            __put_user(cr.pid, &tcr->pid);
+            __put_user(cr.uid, &tcr->uid);
+            __put_user(cr.gid, &tcr->gid);
+            unlock_user_struct(tcr, optval_addr, 1);
+            if (put_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            break;
+        }
         /* Options with 'int' argument.  */
         case TARGET_SO_DEBUG:
             optname = SO_DEBUG;
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 2857805..41f0ff8 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -2336,3 +2336,9 @@ struct target_rlimit64 {
     uint64_t rlim_cur;
     uint64_t rlim_max;
 };
+
+struct target_ucred {
+    uint32_t pid;
+    uint32_t uid;
+    uint32_t gid;
+};
commit 50171d42071d492b916f737b227bc6f3751fee7c
Author: 陳韋任 <chenwj at iis.sinica.edu.tw>
Date:   Tue Nov 8 17:46:44 2011 +0800

    linux-user/main.c: Add option to user-mode emulation so that user can specify log file name
    
      QEMU linux user-mode's default log file name is "/tmp/qemu.log". In order to
    change the log file name, user need to modify the source code then recompile
    QEMU. This patch allow user use "-D logfile" option to specify the log file
    name.
    
    Signed-off-by: Chen Wen-Ren <chenwj at iis.sinica.edu.tw>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/main.c b/linux-user/main.c
index 64d2208..14bf5f0 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2945,6 +2945,11 @@ static void handle_arg_log(const char *arg)
     cpu_set_log(mask);
 }
 
+static void handle_arg_log_filename(const char *arg)
+{
+    cpu_set_log_filename(arg);
+}
+
 static void handle_arg_set_env(const char *arg)
 {
     char *r, *p, *token;
@@ -3125,6 +3130,8 @@ struct qemu_argument arg_table[] = {
 #endif
     {"d",          "QEMU_LOG",         true,  handle_arg_log,
      "options",    "activate log"},
+    {"D",          "QEMU_LOG_FILENAME", true, handle_arg_log_filename,
+     "logfile",     "override default logfile location"},
     {"p",          "QEMU_PAGESIZE",    true,  handle_arg_pagesize,
      "pagesize",   "set the host page size to 'pagesize'"},
     {"singlestep", "QEMU_SINGLESTEP",  false, handle_arg_singlestep,
commit 257450ee59fd7e781cb4e2316ddc845c40b9fc42
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Nov 2 20:23:26 2011 +0100

    linux-user: fake /proc/self/auxv
    
    Gtk tries to read /proc/self/auxv to find its auxv table instead of
    taking it from its own program memory space.
    
    However, when running with linux-user, we see the host's auxv which
    clearly exposes wrong information. so let's instead expose the guest
    memory backed auxv tables via /proc/self/auxv as well.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 5a5fdac..c6bfcd8 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -4639,6 +4639,35 @@ static int open_self_stat(void *cpu_env, int fd)
     return 0;
 }
 
+static int open_self_auxv(void *cpu_env, int fd)
+{
+    TaskState *ts = ((CPUState *)cpu_env)->opaque;
+    abi_ulong auxv = ts->info->saved_auxv;
+    abi_ulong len = ts->info->auxv_len;
+    char *ptr;
+
+    /*
+     * Auxiliary vector is stored in target process stack.
+     * read in whole auxv vector and copy it to file
+     */
+    ptr = lock_user(VERIFY_READ, auxv, len, 0);
+    if (ptr != NULL) {
+        while (len > 0) {
+            ssize_t r;
+            r = write(fd, ptr, len);
+            if (r <= 0) {
+                break;
+            }
+            len -= r;
+            ptr += r;
+        }
+        lseek(fd, 0, SEEK_SET);
+        unlock_user(ptr, auxv, len);
+    }
+
+    return 0;
+}
+
 static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
 {
     struct fake_open {
@@ -4649,6 +4678,7 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
     static const struct fake_open fakes[] = {
         { "/proc/self/maps", open_self_maps },
         { "/proc/self/stat", open_self_stat },
+        { "/proc/self/auxv", open_self_auxv },
         { NULL, NULL }
     };
 
commit 480b8e7dd56746c550a8ae9d7d1ba5d22cf1a4ee
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Nov 2 20:23:25 2011 +0100

    linux-user: fake /proc/self/stat
    
    The boehm gc finds the program's stack starting pointer by
    checking /proc/self/stat. Unfortunately, so far it reads
    qemu's stack pointer which clearly is wrong.
    
    So let's instead fake the file so the guest program sees the
    right address.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 1864d7f..5a5fdac 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -4614,6 +4614,31 @@ static int open_self_maps(void *cpu_env, int fd)
     return 0;
 }
 
+static int open_self_stat(void *cpu_env, int fd)
+{
+    TaskState *ts = ((CPUState *)cpu_env)->opaque;
+    abi_ulong start_stack = ts->info->start_stack;
+    int i;
+
+    for (i = 0; i < 44; i++) {
+      char buf[128];
+      int len;
+      uint64_t val = 0;
+
+      if (i == 27) {
+          /* stack bottom */
+          val = start_stack;
+      }
+      snprintf(buf, sizeof(buf), "%"PRId64 "%c", val, i == 43 ? '\n' : ' ');
+      len = strlen(buf);
+      if (write(fd, buf, len) != len) {
+          return -1;
+      }
+    }
+
+    return 0;
+}
+
 static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
 {
     struct fake_open {
@@ -4623,6 +4648,7 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
     const struct fake_open *fake_open;
     static const struct fake_open fakes[] = {
         { "/proc/self/maps", open_self_maps },
+        { "/proc/self/stat", open_self_stat },
         { NULL, NULL }
     };
 
commit 36c08d498b8ea6995666b805d37c6bb14da66a97
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Nov 2 20:23:24 2011 +0100

    linux-user: fake /proc/self/maps
    
    glibc's pthread_attr_getstack tries to find the stack range from
    /proc/self/maps. Unfortunately, /proc is usually the host's /proc
    which means linux-user guests see qemu's stack there.
    
    Fake the file with a constructed maps entry that exposes the guest's
    stack range.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index e100025..1864d7f 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -4600,6 +4600,20 @@ int get_osversion(void)
     return osversion;
 }
 
+
+static int open_self_maps(void *cpu_env, int fd)
+{
+    TaskState *ts = ((CPUState *)cpu_env)->opaque;
+
+    dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0          [stack]\n",
+                (unsigned long long)ts->info->stack_limit,
+                (unsigned long long)(ts->stack_base + (TARGET_PAGE_SIZE - 1))
+                                     & TARGET_PAGE_MASK,
+                (unsigned long long)ts->stack_base);
+
+    return 0;
+}
+
 static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
 {
     struct fake_open {
@@ -4608,6 +4622,7 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
     };
     const struct fake_open *fake_open;
     static const struct fake_open fakes[] = {
+        { "/proc/self/maps", open_self_maps },
         { NULL, NULL }
     };
 
commit 3be14d05d45774b67398debe42e3bb5524998f4f
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Nov 2 20:23:23 2011 +0100

    linux-user: add open() hijack infrastructure
    
    There are a number of files in /proc that expose host information
    to the guest program. This patch adds infrastructure to override
    the open() syscall for guest programs to enable us to on the fly
    generate guest sensible files.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 2bf9e7e..e100025 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -4600,6 +4600,52 @@ int get_osversion(void)
     return osversion;
 }
 
+static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
+{
+    struct fake_open {
+        const char *filename;
+        int (*fill)(void *cpu_env, int fd);
+    };
+    const struct fake_open *fake_open;
+    static const struct fake_open fakes[] = {
+        { NULL, NULL }
+    };
+
+    for (fake_open = fakes; fake_open->filename; fake_open++) {
+        if (!strncmp(pathname, fake_open->filename,
+                     strlen(fake_open->filename))) {
+            break;
+        }
+    }
+
+    if (fake_open->filename) {
+        const char *tmpdir;
+        char filename[PATH_MAX];
+        int fd, r;
+
+        /* create temporary file to map stat to */
+        tmpdir = getenv("TMPDIR");
+        if (!tmpdir)
+            tmpdir = "/tmp";
+        snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
+        fd = mkstemp(filename);
+        if (fd < 0) {
+            return fd;
+        }
+        unlink(filename);
+
+        if ((r = fake_open->fill(cpu_env, fd))) {
+            close(fd);
+            return r;
+        }
+        lseek(fd, 0, SEEK_SET);
+
+        return fd;
+    }
+
+    return get_errno(open(path(pathname), flags, mode));
+}
+
 /* do_syscall() should always have a single exit point at the end so
    that actions, such as logging of syscall results, can be performed.
    All errnos that do_syscall() returns must be -TARGET_<errcode>. */
@@ -4685,9 +4731,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_NR_open:
         if (!(p = lock_user_string(arg1)))
             goto efault;
-        ret = get_errno(open(path(p),
-                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
-                             arg3));
+        ret = get_errno(do_open(cpu_env, p,
+                                target_to_host_bitmask(arg2, fcntl_flags_tbl),
+                                arg3));
         unlock_user(p, arg1, 0);
         break;
 #if defined(TARGET_NR_openat) && defined(__NR_openat)
commit 125b0f55b63d11518f7d17480c795697c98b9bd3
Author: Alexander Graf <agraf at suse.de>
Date:   Sat Jan 28 21:12:14 2012 +0200

    linux-user: save auxv length
    
    We create our own AUXV segment on stack and save a pointer to it.
    However we don't save the length of it, so any code that wants to
    do anything useful with it later on has to walk it again.
    
    Instead, let's remember the length of our AUXV segment. This
    simplifies later uses by a lot.
    
    (edited by Riku to apply to qemu HEAD)
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Riku Voipio <riku.voipio at iki.fi>

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 845be8b..2fd4a93 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1245,6 +1245,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
                                    struct image_info *interp_info)
 {
     abi_ulong sp;
+    abi_ulong sp_auxv;
     int size;
     int i;
     abi_ulong u_rand_bytes;
@@ -1316,6 +1317,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
         sp -= n; put_user_ual(id, sp);          \
     } while(0)
 
+    sp_auxv = sp;
     NEW_AUX_ENT (AT_NULL, 0);
 
     /* There must be exactly DLINFO_ITEMS entries here.  */
@@ -1346,6 +1348,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
 #undef NEW_AUX_ENT
 
     info->saved_auxv = sp;
+    info->auxv_len = sp_auxv - sp;
 
     sp = loader_build_argptr(envc, argc, sp, p, 0);
     return sp;
@@ -2326,9 +2329,8 @@ static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
 {
     elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
     elf_addr_t orig_auxv = auxv;
-    abi_ulong val;
     void *ptr;
-    int i, len;
+    int len = ts->info->auxv_len;
 
     /*
      * Auxiliary vector is stored in target process stack.  It contains
@@ -2336,15 +2338,6 @@ static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
      * strictly necessary but we do it here for sake of completeness.
      */
 
-    /* find out length of the vector, AT_NULL is terminator */
-    i = len = 0;
-    do {
-        get_user_ual(val, auxv);
-        i += 2;
-        auxv += 2 * sizeof (elf_addr_t);
-    } while (val != AT_NULL);
-    len = i * sizeof (elf_addr_t);
-
     /* read in whole auxv vector and copy it to memelfnote */
     ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
     if (ptr != NULL) {
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 30e2abd..308dbc0 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -48,6 +48,7 @@ struct image_info {
         abi_ulong       code_offset;
         abi_ulong       data_offset;
         abi_ulong       saved_auxv;
+        abi_ulong       auxv_len;
         abi_ulong       arg_start;
         abi_ulong       arg_end;
 	int		personality;
commit d0fd11ffd3e2cb65234da354f14d745e5fbfce67
Author: Riku Voipio <riku.voipio at linaro.org>
Date:   Sat Jan 28 22:00:17 2012 +0200

    linux-user: stack_base is now mandatory on all targets
    
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 55ad9d8..30e2abd 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -123,10 +123,10 @@ typedef struct TaskState {
 #endif
 #if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
     /* Extra fields for semihosted binaries.  */
-    uint32_t stack_base;
     uint32_t heap_base;
     uint32_t heap_limit;
 #endif
+    uint32_t stack_base;
     int used; /* non zero if used */
     struct image_info *info;
     struct linux_binprm *bprm;
commit a496e8eeba51351af136734e475c947a3673dded
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 31 03:46:55 2012 +0100

    PPC: E500: Populate L1CFG0 SPR
    
    When running Linux on e500 with powersave-nap enabled, Linux tries to
    read out the L1CFG0 register and calculates some things from it. Passing
    0 there ends up in a division by 0, resulting in -1, resulting in badness.
    
    So let's populate the L1CFG0 register with reasonable defaults. That way
    guests aren't completely confused.
    
    Reported-by: Shrijeet Mukherjee <shm at cumulusnetworks.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 7848cd7..6253076 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -4434,6 +4434,8 @@ static void init_proc_e500 (CPUPPCState *env, int version)
 {
     uint32_t tlbncfg[2];
     uint64_t ivor_mask = 0x0000000F0000FFFFULL;
+    uint32_t l1cfg0 = 0x3800  /* 8 ways */
+                    | 0x0020; /* 32 kb */
 #if !defined(CONFIG_USER_ONLY)
     int i;
 #endif
@@ -4485,6 +4487,7 @@ static void init_proc_e500 (CPUPPCState *env, int version)
         tlbncfg[1] = gen_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64);
         env->dcache_line_size = 64;
         env->icache_line_size = 64;
+        l1cfg0 |= 0x1000000; /* 64 byte cache block size */
         break;
     default:
         cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]);
@@ -4535,7 +4538,7 @@ static void init_proc_e500 (CPUPPCState *env, int version)
     spr_register(env, SPR_Exxx_L1CFG0, "L1CFG0",
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, &spr_write_generic,
-                 0x00000000);
+                 l1cfg0);
     /* XXX : not implemented */
     spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0",
                  SPR_NOACCESS, SPR_NOACCESS,
commit 8917f4dc62a081c684a1769d38c538df94db9cf0
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 31 03:20:31 2012 +0100

    PPC: e500mc: Enable processor control
    
    The e500mc implements Embedded.Processor Control, so enable it and
    thus enable guests to IPI each other. This makes -smp work with -cpu
    e500mc.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index b14a98c..7848cd7 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -4412,7 +4412,7 @@ static void init_proc_e300 (CPUPPCState *env)
                                 PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL |        \
                                 PPC_FLOAT_STFIWX | PPC_WAIT |               \
                                 PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC)
-#define POWERPC_INSNS2_e500mc  (PPC2_BOOKE206)
+#define POWERPC_INSNS2_e500mc  (PPC2_BOOKE206 | PPC2_PRCNTL)
 #define POWERPC_MSRM_e500mc    (0x000000001402FB36ULL)
 #define POWERPC_MMU_e500mc     (POWERPC_MMU_BOOKE206)
 #define POWERPC_EXCP_e500mc    (POWERPC_EXCP_BOOKE)
commit d5d11a39a8f761c99276f20974de2f25928830c1
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 31 03:19:23 2012 +0100

    PPC: E500: Implement msgsnd
    
    This patch implements the msgsnd instruction. It is part of the
    Embedded.Processor Control specification and allows one CPU to
    IPI another CPU without going through an interrupt controller.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 48ceb61..148543a 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -358,6 +358,7 @@ DEF_HELPER_FLAGS_1(load_sr, TCG_CALL_CONST, tl, tl);
 DEF_HELPER_FLAGS_2(store_sr, TCG_CALL_CONST, void, tl, tl)
 
 DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+DEF_HELPER_1(msgsnd, void, tl)
 DEF_HELPER_1(msgclr, void, tl)
 #endif
 
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index e2f7614..3f4e067 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -4549,4 +4549,22 @@ void helper_msgclr(target_ulong rb)
     env->pending_interrupts &= ~(1 << irq);
 }
 
+void helper_msgsnd(target_ulong rb)
+{
+    int irq = dbell2irq(rb);
+    int pir = rb & DBELL_PIRTAG_MASK;
+    CPUState *cenv;
+
+    if (irq < 0) {
+        return;
+    }
+
+    for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
+        if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
+            cenv->pending_interrupts |= 1 << irq;
+            cpu_interrupt(cenv, CPU_INTERRUPT_HARD);
+        }
+    }
+}
+
 #endif /* !CONFIG_USER_ONLY */
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 01bfe0a..b2780db 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -6236,6 +6236,20 @@ static void gen_msgclr(DisasContext *ctx)
 #endif
 }
 
+static void gen_msgsnd(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(ctx->mem_idx == 0)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+
+    gen_helper_msgsnd(cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+
 /***                      Altivec vector extension                         ***/
 /* Altivec registers moves */
 
@@ -8626,6 +8640,8 @@ GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001,
                PPC_NONE, PPC2_BOOKE206),
 GEN_HANDLER2_E(tlbilx_booke206, "tlbilx", 0x1F, 0x12, 0x00, 0x03800001,
                PPC_NONE, PPC2_BOOKE206),
+GEN_HANDLER2_E(msgsnd, "msgsnd", 0x1F, 0x0E, 0x06, 0x03ff0001,
+               PPC_NONE, PPC2_PRCNTL),
 GEN_HANDLER2_E(msgclr, "msgclr", 0x1F, 0x0E, 0x07, 0x03ff0001,
                PPC_NONE, PPC2_PRCNTL),
 GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE),
commit 9e0b5cb1ecf5543864fad0628a17be23bb617ed7
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 31 03:18:35 2012 +0100

    PPC: E500: Implement msgclr
    
    This patch implements the msgclr instruction. It is part of the
    Embedded.Processor Control specification and clears pending doorbell
    interrupts on the current CPU.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 4798fd5..48ceb61 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -358,6 +358,7 @@ DEF_HELPER_FLAGS_1(load_sr, TCG_CALL_CONST, tl, tl);
 DEF_HELPER_FLAGS_2(store_sr, TCG_CALL_CONST, void, tl, tl)
 
 DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+DEF_HELPER_1(msgclr, void, tl)
 #endif
 
 DEF_HELPER_3(dlmzb, tl, tl, tl, i32)
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 0d1206a..e2f7614 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -4514,4 +4514,39 @@ void helper_booke206_tlbflush(uint32_t type)
     booke206_flush_tlb(env, flags, 1);
 }
 
+/* Embedded.Processor Control */
+static int dbell2irq(target_ulong rb)
+{
+    int msg = rb & DBELL_TYPE_MASK;
+    int irq = -1;
+
+    switch (msg) {
+    case DBELL_TYPE_DBELL:
+        irq = PPC_INTERRUPT_DOORBELL;
+        break;
+    case DBELL_TYPE_DBELL_CRIT:
+        irq = PPC_INTERRUPT_CDOORBELL;
+        break;
+    case DBELL_TYPE_G_DBELL:
+    case DBELL_TYPE_G_DBELL_CRIT:
+    case DBELL_TYPE_G_DBELL_MC:
+        /* XXX implement */
+    default:
+        break;
+    }
+
+    return irq;
+}
+
+void helper_msgclr(target_ulong rb)
+{
+    int irq = dbell2irq(rb);
+
+    if (irq < 0) {
+        return;
+    }
+
+    env->pending_interrupts &= ~(1 << irq);
+}
+
 #endif /* !CONFIG_USER_ONLY */
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 58a4853..01bfe0a 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -6220,6 +6220,22 @@ static void gen_icbt_440(DisasContext *ctx)
      */
 }
 
+/* Embedded.Processor Control */
+
+static void gen_msgclr(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    if (unlikely(ctx->mem_idx == 0)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+
+    gen_helper_msgclr(cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+
 /***                      Altivec vector extension                         ***/
 /* Altivec registers moves */
 
@@ -8610,6 +8626,8 @@ GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001,
                PPC_NONE, PPC2_BOOKE206),
 GEN_HANDLER2_E(tlbilx_booke206, "tlbilx", 0x1F, 0x12, 0x00, 0x03800001,
                PPC_NONE, PPC2_BOOKE206),
+GEN_HANDLER2_E(msgclr, "msgclr", 0x1F, 0x0E, 0x07, 0x03ff0001,
+               PPC_NONE, PPC2_PRCNTL),
 GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE),
 GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE),
 GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC),
commit a9abd71770e64d22ba6cb40c30e4c35998e5c743
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 31 03:17:24 2012 +0100

    PPC: Enable doorbell excp handlers
    
    We already had all the code available to have doorbell exceptions
    be handled properly. It was just disabled.
    
    Enable it, so we can rely on it.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 31a9897..e56fac8 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -2698,22 +2698,10 @@ static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
                   "Performance counter exception is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
-        /* XXX: TODO */
-        cpu_abort(env,
-                  "Embedded doorbell interrupt is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
-        switch (excp_model) {
-        case POWERPC_EXCP_BOOKE:
-            srr0 = SPR_BOOKE_CSRR0;
-            srr1 = SPR_BOOKE_CSRR1;
-            break;
-        default:
-            break;
-        }
-        /* XXX: TODO */
-        cpu_abort(env, "Embedded doorbell critical interrupt "
-                  "is not implemented yet !\n");
+        srr0 = SPR_BOOKE_CSRR0;
+        srr1 = SPR_BOOKE_CSRR1;
         goto store_next;
     case POWERPC_EXCP_RESET:     /* System reset exception                   */
         if (msr_pow) {
commit 3f9f6a50824f6e6728cbcc008891296102fc045a
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 31 03:13:30 2012 +0100

    PPC: Add CPU feature for processor control
    
    We're soon going to implement processor control features. Add the
    feature flag, so we're well prepared.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index f9cea3d..fbcf488 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1916,8 +1916,10 @@ enum {
     PPC2_VSX           = 0x0000000000000002ULL,
     /* Decimal Floating Point (DFP)                                          */
     PPC2_DFP           = 0x0000000000000004ULL,
+    /* Embedded.Processor Control                                            */
+    PPC2_PRCNTL        = 0x0000000000000008ULL,
 
-#define PPC_TCG_INSNS2 (PPC2_BOOKE206)
+#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_PRCNTL)
 };
 
 /*****************************************************************************/
commit 58e00a2432ace900eca96c1dec114a8be75c2de8
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 31 03:11:32 2012 +0100

    PPC: E500: Add doorbell defines
    
    We're going to introduce doorbell instructions (called processor
    control in the spec) soon. Add some defines for easier patch
    readability later.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index c7a6427..f9cea3d 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -858,6 +858,22 @@ enum {
 #define BOOKE206_MAX_TLBN      4
 
 /*****************************************************************************/
+/* Embedded.Processor Control */
+
+#define DBELL_TYPE_SHIFT               27
+#define DBELL_TYPE_MASK                (0x1f << DBELL_TYPE_SHIFT)
+#define DBELL_TYPE_DBELL               (0x00 << DBELL_TYPE_SHIFT)
+#define DBELL_TYPE_DBELL_CRIT          (0x01 << DBELL_TYPE_SHIFT)
+#define DBELL_TYPE_G_DBELL             (0x02 << DBELL_TYPE_SHIFT)
+#define DBELL_TYPE_G_DBELL_CRIT        (0x03 << DBELL_TYPE_SHIFT)
+#define DBELL_TYPE_G_DBELL_MC          (0x04 << DBELL_TYPE_SHIFT)
+
+#define DBELL_BRDCAST                  (1 << 26)
+#define DBELL_LPIDTAG_SHIFT            14
+#define DBELL_LPIDTAG_MASK             (0xfff << DBELL_LPIDTAG_SHIFT)
+#define DBELL_PIRTAG_MASK              0x3fff
+
+/*****************************************************************************/
 /* The whole PowerPC CPU context */
 #define NB_MMU_MODES 3
 
commit 0ef654e3fc40d15f9a0467dae8b9548b21d3ab93
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 31 03:09:58 2012 +0100

    PPC: E500: Add some more excp vectors
    
    Our EXCP list is getting outdated. By now, 3 new exception vectors have
    been introduced. Update the list so we have everything at one place.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 668ddf3..c7a6427 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -187,7 +187,10 @@ enum {
     POWERPC_EXCP_EPERFM   = 35, /* Embedded performance monitor interrupt    */
     POWERPC_EXCP_DOORI    = 36, /* Embedded doorbell interrupt               */
     POWERPC_EXCP_DOORCI   = 37, /* Embedded doorbell critical interrupt      */
-    /* Vectors 38 to 63 are reserved                                         */
+    POWERPC_EXCP_GDOORI   = 38, /* Embedded guest doorbell interrupt         */
+    POWERPC_EXCP_GDOORCI  = 39, /* Embedded guest doorbell critical interrupt*/
+    POWERPC_EXCP_HYPPRIV  = 41, /* Embedded hypervisor priv instruction      */
+    /* Vectors 42 to 63 are reserved                                         */
     /* Exceptions defined in the PowerPC server specification                */
     POWERPC_EXCP_RESET    = 64, /* System reset exception                    */
     POWERPC_EXCP_DSEG     = 65, /* Data segment exception                    */
commit a9c5eb0db1739d53e7a3b1491e496eb25d3db3f4
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Jan 25 18:28:05 2012 +0100

    KVM: Fix compilation on non-x86
    
    Commit 84b058d broke compilation for KVM on non-x86 targets, which
    don't have KVM_CAP_IRQ_ROUTING defined.
    
    Fix by not using the unavailable constant when it's not around.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/kvm-all.c b/kvm-all.c
index 7d4e544..0b87658 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1306,7 +1306,11 @@ int kvm_has_many_ioeventfds(void)
 
 int kvm_has_gsi_routing(void)
 {
+#ifdef KVM_CAP_IRQ_ROUTING
     return kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING);
+#else
+    return false;
+#endif
 }
 
 int kvm_allows_irq0_override(void)
commit 21a0b6ed1dd9f1d8e3d953954847776c8697bd99
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Jan 25 17:06:30 2012 +0100

    PPC: booke206: move avail check to tlbwe
    
    We can have TLBs that only support a single page size. This is defined
    by the absence of the AVAIL flag in TLBnCFG. If this is the case, we
    currently write invalid size info into the TLB, but override it on
    internal fault.
    
    Let's move the check over to tlbwe, so we don't have the AVAIL check in
    the hotter fault path.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 672494c..31a9897 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1298,13 +1298,7 @@ target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb)
     int tlbm_size;
 
     tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
-
-    if (tlbncfg & TLBnCFG_AVAIL) {
-        tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
-    } else {
-        tlbm_size = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
-        tlbm_size <<= 1;
-    }
+    tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
 
     return 1024ULL << tlbm_size;
 }
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index be4e539..0d1206a 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -4282,6 +4282,15 @@ void helper_booke206_tlbwe(void)
     tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
                   env->spr[SPR_BOOKE_MAS3];
     tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
+
+    /* MAV 1.0 only */
+    if (!(tlbncfg & TLBnCFG_AVAIL)) {
+        /* force !AVAIL TLB entries to correct page size */
+        tlb->mas1 &= ~MAS1_TSIZE_MASK;
+        /* XXX can be configured in MMUCSR0 */
+        tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
+    }
+
     /* XXX needs to change when supporting 64-bit e500 */
     tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff;
 
commit 3f162d119ef52fda714ebb498fcb4f4b7c354d38
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Jan 25 16:27:26 2012 +0100

    PPC: booke206: Check for TLB overrun
    
    Our internal helpers to fetch TLB entries were not able to tell us
    that an entry doesn't even exist. Pass an error out if we hit such
    a case to not accidently pass beyond the TLB array.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 1026254..668ddf3 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -2112,6 +2112,10 @@ static inline ppcmas_tlb_t *booke206_get_tlbm(CPUState *env, const int tlbn,
     ea &= (1 << (tlb_bits - ways_bits)) - 1;
     r = (ea << ways_bits) | way;
 
+    if (r >= booke206_tlb_size(env, tlbn)) {
+        return NULL;
+    }
+
     /* bump up to tlbn index */
     for (i = 0; i < tlbn; i++) {
         r += booke206_tlb_size(env, i);
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 2ce2d92..672494c 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1448,6 +1448,9 @@ static int mmubooke206_get_physical_address(CPUState *env, mmu_ctx_t *ctx,
 
         for (j = 0; j < ways; j++) {
             tlb = booke206_get_tlbm(env, i, address, j);
+            if (!tlb) {
+                continue;
+            }
             ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
                                         rw, access_type);
             if (ret != -1) {
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 1f1fa09..be4e539 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -4260,6 +4260,12 @@ void helper_booke206_tlbwe(void)
 
     tlb = booke206_cur_tlb(env);
 
+    if (!tlb) {
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+                                   POWERPC_EXCP_INVAL |
+                                   POWERPC_EXCP_INVAL_INVAL);
+    }
+
     /* check that we support the targeted size */
     size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
     size_ps = booke206_tlbnps(env, tlbn);
@@ -4311,7 +4317,11 @@ void helper_booke206_tlbre(void)
     ppcmas_tlb_t *tlb = NULL;
 
     tlb = booke206_cur_tlb(env);
-    booke206_tlb_to_mas(env, tlb);
+    if (!tlb) {
+        env->spr[SPR_BOOKE_MAS1] = 0;
+    } else {
+        booke206_tlb_to_mas(env, tlb);
+    }
 }
 
 void helper_booke206_tlbsx(target_ulong address)
@@ -4330,6 +4340,10 @@ void helper_booke206_tlbsx(target_ulong address)
         for (j = 0; j < ways; j++) {
             tlb = booke206_get_tlbm(env, i, address, j);
 
+            if (!tlb) {
+                continue;
+            }
+
             if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
                 continue;
             }
@@ -4373,6 +4387,9 @@ static inline void booke206_invalidate_ea_tlb(CPUState *env, int tlbn,
 
     for (i = 0; i < ways; i++) {
         ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
+        if (!tlb) {
+            continue;
+        }
         mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
         if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
             !(tlb->mas1 & MAS1_IPROT)) {
@@ -4453,6 +4470,9 @@ void helper_booke206_tlbilx3(target_ulong address)
 
         for (j = 0; j < ways; j++) {
             tlb = booke206_get_tlbm(env, i, address, j);
+            if (!tlb) {
+                continue;
+            }
             if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
                 (tlb->mas1 & MAS1_IPROT) ||
                 ((tlb->mas1 & MAS1_IND) != ind) ||
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index d8ef719..58a4853 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -6088,6 +6088,7 @@ static void gen_tlbwe_booke206(DisasContext *ctx)
         gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
         return;
     }
+    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_booke206_tlbwe();
 #endif
 }
commit 6d3db821c18fdc9727108b5b4bbb38cb7ab5c0e6
Author: Alexander Graf <agraf at suse.de>
Date:   Fri Jan 20 04:09:15 2012 +0100

    PPC: booke206: Implement tlbilx
    
    The PowerPC 2.06 BookE ISA defines an opcode called "tlbilx" which is used
    to flush TLB entries. It's the recommended way of flushing in virtualized
    environments.
    
    So far we got away without implementing it, but Linux for e500mc uses this
    instruction, so we better add it :).
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 470e42f..4798fd5 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -336,6 +336,9 @@ DEF_HELPER_0(booke206_tlbre, void)
 DEF_HELPER_0(booke206_tlbwe, void)
 DEF_HELPER_1(booke206_tlbsx, void, tl)
 DEF_HELPER_1(booke206_tlbivax, void, tl)
+DEF_HELPER_1(booke206_tlbilx0, void, tl)
+DEF_HELPER_1(booke206_tlbilx1, void, tl)
+DEF_HELPER_1(booke206_tlbilx3, void, tl)
 DEF_HELPER_1(booke206_tlbflush, void, i32)
 DEF_HELPER_2(booke_setpid, void, i32, tl)
 DEF_HELPER_1(6xx_tlbd, void, tl)
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 3b197f2..1f1fa09 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -4406,6 +4406,70 @@ void helper_booke206_tlbivax(target_ulong address)
     }
 }
 
+void helper_booke206_tlbilx0(target_ulong address)
+{
+    /* XXX missing LPID handling */
+    booke206_flush_tlb(env, -1, 1);
+}
+
+void helper_booke206_tlbilx1(target_ulong address)
+{
+    int i, j;
+    int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
+    ppcmas_tlb_t *tlb = env->tlb.tlbm;
+    int tlb_size;
+
+    /* XXX missing LPID handling */
+    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+        tlb_size = booke206_tlb_size(env, i);
+        for (j = 0; j < tlb_size; j++) {
+            if (!(tlb[j].mas1 & MAS1_IPROT) &&
+                ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
+                tlb[j].mas1 &= ~MAS1_VALID;
+            }
+        }
+        tlb += booke206_tlb_size(env, i);
+    }
+    tlb_flush(env, 1);
+}
+
+void helper_booke206_tlbilx3(target_ulong address)
+{
+    int i, j;
+    ppcmas_tlb_t *tlb;
+    int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
+    int pid = tid >> MAS6_SPID_SHIFT;
+    int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
+    int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
+    /* XXX check for unsupported isize and raise an invalid opcode then */
+    int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
+    /* XXX implement MAV2 handling */
+    bool mav2 = false;
+
+    /* XXX missing LPID handling */
+    /* flush by pid and ea */
+    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+        int ways = booke206_tlb_ways(env, i);
+
+        for (j = 0; j < ways; j++) {
+            tlb = booke206_get_tlbm(env, i, address, j);
+            if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
+                (tlb->mas1 & MAS1_IPROT) ||
+                ((tlb->mas1 & MAS1_IND) != ind) ||
+                ((tlb->mas8 & MAS8_TGS) != sgs)) {
+                continue;
+            }
+            if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
+                /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
+                continue;
+            }
+            /* XXX e500mc doesn't match SAS, but other cores might */
+            tlb->mas1 &= ~MAS1_VALID;
+        }
+    }
+    tlb_flush(env, 1);
+}
+
 void helper_booke206_tlbflush(uint32_t type)
 {
     int flags = 0;
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index adde65b..d8ef719 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -6110,6 +6110,39 @@ static void gen_tlbivax_booke206(DisasContext *ctx)
 #endif
 }
 
+static void gen_tlbilx_booke206(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+    TCGv t0;
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+        return;
+    }
+
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+
+    switch((ctx->opcode >> 21) & 0x3) {
+    case 0:
+        gen_helper_booke206_tlbilx0(t0);
+        break;
+    case 1:
+        gen_helper_booke206_tlbilx1(t0);
+        break;
+    case 3:
+        gen_helper_booke206_tlbilx3(t0);
+        break;
+    default:
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+        break;
+    }
+
+    tcg_temp_free(t0);
+#endif
+}
+
 
 /* wrtee */
 static void gen_wrtee(DisasContext *ctx)
@@ -8574,6 +8607,8 @@ GEN_HANDLER2_E(tlbwe_booke206, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001,
                PPC_NONE, PPC2_BOOKE206),
 GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001,
                PPC_NONE, PPC2_BOOKE206),
+GEN_HANDLER2_E(tlbilx_booke206, "tlbilx", 0x1F, 0x12, 0x00, 0x03800001,
+               PPC_NONE, PPC2_BOOKE206),
 GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE),
 GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE),
 GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC),
commit 5935ee072d6fbcdf28ff6132ba6d8c3a1356bb0a
Author: Alexander Graf <agraf at suse.de>
Date:   Fri Jan 20 04:07:51 2012 +0100

    PPC: booke206: Check for min/max TLB entry size
    
    When setting a TLB entry, we need to check if the TLB we're putting it in
    actually supports the given size. According to the 2.06 PowerPC ISA, a
    value that's out of range can either be redefined to something implementation
    dependent or we can raise an illegal opcode exception. We do the latter.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 6339c95..3b197f2 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -4228,6 +4228,7 @@ void helper_booke206_tlbwe(void)
 {
     uint32_t tlbncfg, tlbn;
     ppcmas_tlb_t *tlb;
+    uint32_t size_tlb, size_ps;
 
     switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
     case MAS0_WQ_ALWAYS:
@@ -4259,6 +4260,16 @@ void helper_booke206_tlbwe(void)
 
     tlb = booke206_cur_tlb(env);
 
+    /* check that we support the targeted size */
+    size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
+    size_ps = booke206_tlbnps(env, tlbn);
+    if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
+        !(size_ps & (1 << size_tlb))) {
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+                                   POWERPC_EXCP_INVAL |
+                                   POWERPC_EXCP_INVAL_INVAL);
+    }
+
     if (msr_gs) {
         cpu_abort(env, "missing HV implementation\n");
     }
commit a1ef618a3768cc114b6fae4099af95df87654a04
Author: Alexander Graf <agraf at suse.de>
Date:   Sat Jan 21 04:45:46 2012 +0100

    PPC: booke: add tlbnps handling
    
    When using MAV 2.0 TLB registers, we have another range of TLB registers
    available to read the supported page sizes from.
    
    Add SPR definitions for those and add a helper function that we can use
    to receive such a bitmap even when using MAV 1.0.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 6f4cdde..1026254 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1355,6 +1355,10 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
 #define SPR_BOOKE_DVC2        (0x13F)
 #define SPR_BOOKE_TSR         (0x150)
 #define SPR_BOOKE_TCR         (0x154)
+#define SPR_BOOKE_TLB0PS      (0x158)
+#define SPR_BOOKE_TLB1PS      (0x159)
+#define SPR_BOOKE_TLB2PS      (0x15A)
+#define SPR_BOOKE_TLB3PS      (0x15B)
 #define SPR_BOOKE_IVOR0       (0x190)
 #define SPR_BOOKE_IVOR1       (0x191)
 #define SPR_BOOKE_IVOR2       (0x192)
@@ -2116,6 +2120,27 @@ static inline ppcmas_tlb_t *booke206_get_tlbm(CPUState *env, const int tlbn,
     return &env->tlb.tlbm[r];
 }
 
+/* returns bitmap of supported page sizes for a given TLB */
+static inline uint32_t booke206_tlbnps(CPUState *env, const int tlbn)
+{
+    bool mav2 = false;
+    uint32_t ret = 0;
+
+    if (mav2) {
+        ret = env->spr[SPR_BOOKE_TLB0PS + tlbn];
+    } else {
+        uint32_t tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
+        uint32_t min = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
+        uint32_t max = (tlbncfg & TLBnCFG_MAXSIZE) >> TLBnCFG_MAXSIZE_SHIFT;
+        int i;
+        for (i = min; i <= max; i++) {
+            ret |= (1 << (i << 1));
+        }
+    }
+
+    return ret;
+}
+
 #endif
 
 extern void (*cpu_ppc_hypercall)(CPUState *);
commit ffba87862b37f1d7762370c8d31b09f6e359ff09
Author: Alexander Graf <agraf at suse.de>
Date:   Fri Jan 20 04:06:18 2012 +0100

    PPC: booke206: allow NULL raddr in ppcmas_tlb_check
    
    We might want to call the tlb check function without actually caring about
    the real address resolution. Check if we really should write the value
    back.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 5847453..2ce2d92 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1338,7 +1338,10 @@ int ppcmas_tlb_check(CPUState *env, ppcmas_tlb_t *tlb,
     if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
         return -1;
     }
-    *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
+
+    if (raddrp) {
+        *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
+    }
 
     return 0;
 }
commit dcb2b9e1003a9179650b44c747faa4e5767ce92b
Author: Alexander Graf <agraf at suse.de>
Date:   Sat Jan 21 03:48:58 2012 +0100

    PPC: rename msync to msync_4xx
    
    The msync instruction as defined today is only valid on 4xx cores, not
    on e500 which also supports msync, but treats it the same way as sync.
    
    Rename it to reflect that it's 4xx only.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 18d52a9..adde65b 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -6172,7 +6172,7 @@ static void gen_mbar(DisasContext *ctx)
 }
 
 /* msync replaces sync on 440 */
-static void gen_msync(DisasContext *ctx)
+static void gen_msync_4xx(DisasContext *ctx)
 {
     /* interpreted as no-op */
 }
@@ -8579,7 +8579,7 @@ GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE),
 GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC),
 GEN_HANDLER_E(mbar, 0x1F, 0x16, 0x1a, 0x001FF801,
               PPC_BOOKE, PPC2_BOOKE206),
-GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE),
+GEN_HANDLER(msync_4xx, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE),
 GEN_HANDLER2_E(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001,
                PPC_BOOKE, PPC2_BOOKE206),
 GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC),
commit 53319166318f365db3bb72cf5a80618211ecf9df
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jan 19 19:51:50 2012 +0100

    PPC: e500: msync is 440 only, e500 has real sync
    
    The e500 CPUs don't use 440's msync which falls on the same opcode IDs,
    but instead use the real powerpc sync instruction. This is important,
    since the invalid mask differs between the two.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 66eae30..18d52a9 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -8579,8 +8579,7 @@ GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE),
 GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC),
 GEN_HANDLER_E(mbar, 0x1F, 0x16, 0x1a, 0x001FF801,
               PPC_BOOKE, PPC2_BOOKE206),
-GEN_HANDLER_E(msync, 0x1F, 0x16, 0x12, 0x03FFF801,
-              PPC_BOOKE, PPC2_BOOKE206),
+GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE),
 GEN_HANDLER2_E(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001,
                PPC_BOOKE, PPC2_BOOKE206),
 GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC),
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index f5fcd1e..b14a98c 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -4371,7 +4371,7 @@ static void init_proc_e300 (CPUPPCState *env)
                                 PPC_WRTEE | PPC_RFDI |                  \
                                 PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
                                 PPC_CACHE_DCBZ | PPC_CACHE_DCBA |       \
-                                PPC_MEM_TLBSYNC | PPC_TLBIVAX)
+                                PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC)
 #define POWERPC_INSNS2_e500v1  (PPC2_BOOKE206)
 #define POWERPC_MSRM_e500v1    (0x000000000606FF30ULL)
 #define POWERPC_MMU_e500v1     (POWERPC_MMU_BOOKE206)
@@ -4390,7 +4390,7 @@ static void init_proc_e300 (CPUPPCState *env)
                                 PPC_WRTEE | PPC_RFDI |                  \
                                 PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
                                 PPC_CACHE_DCBZ | PPC_CACHE_DCBA |       \
-                                PPC_MEM_TLBSYNC | PPC_TLBIVAX)
+                                PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC)
 #define POWERPC_INSNS2_e500v2  (PPC2_BOOKE206)
 #define POWERPC_MSRM_e500v2    (0x000000000606FF30ULL)
 #define POWERPC_MMU_e500v2     (POWERPC_MMU_BOOKE206)
@@ -4411,7 +4411,7 @@ static void init_proc_e300 (CPUPPCState *env)
                                 PPC_FLOAT | PPC_FLOAT_FRES |                \
                                 PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL |        \
                                 PPC_FLOAT_STFIWX | PPC_WAIT |               \
-                                PPC_MEM_TLBSYNC | PPC_TLBIVAX)
+                                PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC)
 #define POWERPC_INSNS2_e500mc  (PPC2_BOOKE206)
 #define POWERPC_MSRM_e500mc    (0x000000001402FB36ULL)
 #define POWERPC_MMU_e500mc     (POWERPC_MMU_BOOKE206)
commit 2c9732dbc0df8c7c40c945b6558da8a448b8c069
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jan 19 18:57:26 2012 +0100

    PPC: e500mc: add missing IVORs to bitmap
    
    E500mc supports IVORs 36-41. Add them to the support mask. Drop SPE
    support too.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 83348b5..f5fcd1e 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -4433,6 +4433,7 @@ enum fsl_e500_version {
 static void init_proc_e500 (CPUPPCState *env, int version)
 {
     uint32_t tlbncfg[2];
+    uint64_t ivor_mask = 0x0000000F0000FFFFULL;
 #if !defined(CONFIG_USER_ONLY)
     int i;
 #endif
@@ -4444,7 +4445,10 @@ static void init_proc_e500 (CPUPPCState *env, int version)
      *     complain when accessing them.
      * gen_spr_BookE(env, 0x0000000F0000FD7FULL);
      */
-    gen_spr_BookE(env, 0x0000000F0000FFFFULL);
+    if (version == fsl_e500mc) {
+        ivor_mask = 0x000003FE0000FFFFULL;
+    }
+    gen_spr_BookE(env, ivor_mask);
     /* Processor identification */
     spr_register(env, SPR_BOOKE_PIR, "PIR",
                  SPR_NOACCESS, SPR_NOACCESS,
commit e9205258ac7de7aba579ee07efc49dda66f51e63
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jan 19 19:31:51 2012 +0100

    PPC: Add IVOR 38-42
    
    Our code only knows IVORs up to 37. Add the new ones defined in ISA 2.06
    from 38 - 42.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Reviewed-by: Andreas Färber <afaerber at suse.de>

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 2d67d1f..6f4cdde 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1371,6 +1371,11 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
 #define SPR_BOOKE_IVOR13      (0x19D)
 #define SPR_BOOKE_IVOR14      (0x19E)
 #define SPR_BOOKE_IVOR15      (0x19F)
+#define SPR_BOOKE_IVOR38      (0x1B0)
+#define SPR_BOOKE_IVOR39      (0x1B1)
+#define SPR_BOOKE_IVOR40      (0x1B2)
+#define SPR_BOOKE_IVOR41      (0x1B3)
+#define SPR_BOOKE_IVOR42      (0x1B4)
 #define SPR_BOOKE_SPEFSCR     (0x200)
 #define SPR_Exxx_BBEAR        (0x201)
 #define SPR_Exxx_BBTAR        (0x202)
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 4d692d0..83348b5 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -526,26 +526,27 @@ static void spr_write_excp_prefix (void *opaque, int sprn, int gprn)
 static void spr_write_excp_vector (void *opaque, int sprn, int gprn)
 {
     DisasContext *ctx = opaque;
+    int sprn_offs;
 
     if (sprn >= SPR_BOOKE_IVOR0 && sprn <= SPR_BOOKE_IVOR15) {
-        TCGv t0 = tcg_temp_new();
-        tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, ivor_mask));
-        tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
-        tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, excp_vectors[sprn - SPR_BOOKE_IVOR0]));
-        gen_store_spr(sprn, t0);
-        tcg_temp_free(t0);
+        sprn_offs = sprn - SPR_BOOKE_IVOR0;
     } else if (sprn >= SPR_BOOKE_IVOR32 && sprn <= SPR_BOOKE_IVOR37) {
-        TCGv t0 = tcg_temp_new();
-        tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, ivor_mask));
-        tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
-        tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, excp_vectors[sprn - SPR_BOOKE_IVOR32 + 32]));
-        gen_store_spr(sprn, t0);
-        tcg_temp_free(t0);
+        sprn_offs = sprn - SPR_BOOKE_IVOR32 + 32;
+    } else if (sprn >= SPR_BOOKE_IVOR38 && sprn <= SPR_BOOKE_IVOR42) {
+        sprn_offs = sprn - SPR_BOOKE_IVOR38 + 38;
     } else {
         printf("Trying to write an unknown exception vector %d %03x\n",
                sprn, sprn);
         gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
     }
+
+    TCGv t0 = tcg_temp_new();
+    tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, ivor_mask));
+    tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
+    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, excp_vectors[sprn_offs]));
+    gen_store_spr(sprn, t0);
+    tcg_temp_free(t0);
 }
 #endif
 
@@ -1434,8 +1435,8 @@ static void gen_spr_BookE (CPUPPCState *env, uint64_t ivor_mask)
         SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
         SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
         SPR_BOOKE_IVOR32, SPR_BOOKE_IVOR33, SPR_BOOKE_IVOR34, SPR_BOOKE_IVOR35,
-        SPR_BOOKE_IVOR36, SPR_BOOKE_IVOR37, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
-        SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
+        SPR_BOOKE_IVOR36, SPR_BOOKE_IVOR37, SPR_BOOKE_IVOR38, SPR_BOOKE_IVOR39,
+        SPR_BOOKE_IVOR40, SPR_BOOKE_IVOR41, SPR_BOOKE_IVOR42, SPR_BOOKE_IVORxx,
         SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
         SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
         SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
commit a31be480a0b4ede50f260dd29971dca961da3a2c
Author: Alexander Graf <agraf at suse.de>
Date:   Fri Jan 6 04:02:24 2012 +0100

    PPC: KVM: Update HIOR code to new interface
    
    Unfortunately the HIOR setting code slipped into upstream QEMU
    before it was pulled into upstream KVM. And since Murphy is always
    right, comments on the patches only emerged on the pull request
    leading to changes in the interface.
    
    So here's an update to the HIOR setting. While at it, I also relaxed
    it a bit since for HV KVM we can already run fine without and 3.2
    works just fine with HV KVM but when not setting HIOR. We will only
    need this when running PAPR in PR KVM.
    
    Since we accidently changed the ABI and API along the way, we have
    to update the underlying kernel headers together with the code that
    uses it to not break bisectability.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
index 1f0cb55..b921c3f 100644
--- a/linux-headers/asm-powerpc/kvm.h
+++ b/linux-headers/asm-powerpc/kvm.h
@@ -324,6 +324,6 @@ struct kvm_book3e_206_tlb_params {
 	__u32 reserved[8];
 };
 
-#define KVM_ONE_REG_PPC_HIOR	KVM_ONE_REG_PPC | 0x100
+#define KVM_REG_PPC_HIOR	(KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1)
 
 #endif /* __LINUX_KVM_POWERPC_H */
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 4847813..f6b5343 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -684,30 +684,33 @@ struct kvm_dirty_tlb {
 
 /* Available with KVM_CAP_ONE_REG */
 
-#define KVM_ONE_REG_GENERIC		0x0000000000000000ULL
+#define KVM_REG_ARCH_MASK	0xff00000000000000ULL
+#define KVM_REG_GENERIC		0x0000000000000000ULL
 
 /*
  * Architecture specific registers are to be defined in arch headers and
  * ORed with the arch identifier.
  */
-#define KVM_ONE_REG_PPC			0x1000000000000000ULL
-#define KVM_ONE_REG_X86			0x2000000000000000ULL
-#define KVM_ONE_REG_IA64		0x3000000000000000ULL
-#define KVM_ONE_REG_ARM			0x4000000000000000ULL
-#define KVM_ONE_REG_S390		0x5000000000000000ULL
+#define KVM_REG_PPC		0x1000000000000000ULL
+#define KVM_REG_X86		0x2000000000000000ULL
+#define KVM_REG_IA64		0x3000000000000000ULL
+#define KVM_REG_ARM		0x4000000000000000ULL
+#define KVM_REG_S390		0x5000000000000000ULL
+
+#define KVM_REG_SIZE_SHIFT	52
+#define KVM_REG_SIZE_MASK	0x00f0000000000000ULL
+#define KVM_REG_SIZE_U8		0x0000000000000000ULL
+#define KVM_REG_SIZE_U16	0x0010000000000000ULL
+#define KVM_REG_SIZE_U32	0x0020000000000000ULL
+#define KVM_REG_SIZE_U64	0x0030000000000000ULL
+#define KVM_REG_SIZE_U128	0x0040000000000000ULL
+#define KVM_REG_SIZE_U256	0x0050000000000000ULL
+#define KVM_REG_SIZE_U512	0x0060000000000000ULL
+#define KVM_REG_SIZE_U1024	0x0070000000000000ULL
 
 struct kvm_one_reg {
 	__u64 id;
-	union {
-		__u8 reg8;
-		__u16 reg16;
-		__u32 reg32;
-		__u64 reg64;
-		__u8 reg128[16];
-		__u8 reg256[32];
-		__u8 reg512[64];
-		__u8 reg1024[128];
-	} u;
+	__u64 addr;
 };
 
 /*
@@ -850,7 +853,7 @@ struct kvm_s390_ucas_mapping {
 /* Available with KVM_CAP_SW_TLB */
 #define KVM_DIRTY_TLB		  _IOW(KVMIO,  0xaa, struct kvm_dirty_tlb)
 /* Available with KVM_CAP_ONE_REG */
-#define KVM_GET_ONE_REG		  _IOWR(KVMIO, 0xab, struct kvm_one_reg)
+#define KVM_GET_ONE_REG		  _IOW(KVMIO,  0xab, struct kvm_one_reg)
 #define KVM_SET_ONE_REG		  _IOW(KVMIO,  0xac, struct kvm_one_reg)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index ce8ac5b..50cfa02 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -740,6 +740,7 @@ void kvmppc_set_papr(CPUState *env)
     struct kvm_one_reg reg = {};
     struct kvm_sregs sregs = {};
     int ret;
+    uint64_t hior = env->spr[SPR_HIOR];
 
     cap.cap = KVM_CAP_PPC_PAPR;
     ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &cap);
@@ -755,11 +756,14 @@ void kvmppc_set_papr(CPUState *env)
      *     Once we have qdev CPUs, move HIOR to a qdev property and
      *     remove this chunk.
      */
-    reg.id = KVM_ONE_REG_PPC_HIOR;
-    reg.u.reg64 = env->spr[SPR_HIOR];
+    reg.id = KVM_REG_PPC_HIOR;
+    reg.addr = (uintptr_t)&hior;
     ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &reg);
     if (ret) {
-        goto fail;
+        fprintf(stderr, "Couldn't set HIOR. Maybe you're running an old \n"
+                        "kernel with support for HV KVM but no PAPR PR \n"
+                        "KVM in which case things will work. If they don't \n"
+                        "please update your host kernel!\n");
     }
 
     /* Set SDR1 so kernel space finds the HTAB */
commit 1529ae1bc61a15e9a243dcbad70c95dfcdd1f0c5
Author: Alexander Graf <agraf at suse.de>
Date:   Fri Jan 20 14:41:12 2012 +0100

    KVM: Update headers (except HIOR mess)
    
    This patch is basically what ./scripts/update-linux-headers.sh against
    upstream KVM's next branch outputs except that all the HIOR bits are
    removed. These we have to update with the code that uses them.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
index fb3fddc..1f0cb55 100644
--- a/linux-headers/asm-powerpc/kvm.h
+++ b/linux-headers/asm-powerpc/kvm.h
@@ -265,12 +265,9 @@ struct kvm_debug_exit_arch {
 struct kvm_guest_debug_arch {
 };
 
-#define KVM_REG_MASK		0x001f
-#define KVM_REG_EXT_MASK	0xffe0
-#define KVM_REG_GPR		0x0000
-#define KVM_REG_FPR		0x0020
-#define KVM_REG_QPR		0x0040
-#define KVM_REG_FQPR		0x0060
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+};
 
 #define KVM_INTERRUPT_SET	-1U
 #define KVM_INTERRUPT_UNSET	-2U
diff --git a/linux-headers/asm-powerpc/kvm_para.h b/linux-headers/asm-powerpc/kvm_para.h
index ad58c90..c047a84 100644
--- a/linux-headers/asm-powerpc/kvm_para.h
+++ b/linux-headers/asm-powerpc/kvm_para.h
@@ -22,6 +22,16 @@
 
 #include <linux/types.h>
 
+/*
+ * Additions to this struct must only occur at the end, and should be
+ * accompanied by a KVM_MAGIC_FEAT flag to advertise that they are present
+ * (albeit not necessarily relevant to the current target hardware platform).
+ *
+ * Struct fields are always 32 or 64 bit aligned, depending on them being 32
+ * or 64 bit wide respectively.
+ *
+ * See Documentation/virtual/kvm/ppc-pv.txt
+ */
 struct kvm_vcpu_arch_shared {
 	__u64 scratch1;
 	__u64 scratch2;
@@ -33,11 +43,35 @@ struct kvm_vcpu_arch_shared {
 	__u64 sprg3;
 	__u64 srr0;
 	__u64 srr1;
-	__u64 dar;
+	__u64 dar;		/* dear on BookE */
 	__u64 msr;
 	__u32 dsisr;
 	__u32 int_pending;	/* Tells the guest if we have an interrupt */
 	__u32 sr[16];
+	__u32 mas0;
+	__u32 mas1;
+	__u64 mas7_3;
+	__u64 mas2;
+	__u32 mas4;
+	__u32 mas6;
+	__u32 esr;
+	__u32 pir;
+
+	/*
+	 * SPRG4-7 are user-readable, so we can only keep these consistent
+	 * between the shared area and the real registers when there's an
+	 * intervening exit to KVM.  This also applies to SPRG3 on some
+	 * chips.
+	 *
+	 * This suffices for access by guest userspace, since in PR-mode
+	 * KVM, an exit must occur when changing the guest's MSR[PR].
+	 * If the guest kernel writes to SPRG3-7 via the shared area, it
+	 * must also use the shared area for reading while in kernel space.
+	 */
+	__u64 sprg4;
+	__u64 sprg5;
+	__u64 sprg6;
+	__u64 sprg7;
 };
 
 #define KVM_SC_MAGIC_R0		0x4b564d21 /* "KVM!" */
@@ -47,7 +81,10 @@ struct kvm_vcpu_arch_shared {
 
 #define KVM_FEATURE_MAGIC_PAGE	1
 
-#define KVM_MAGIC_FEAT_SR	(1 << 0)
+#define KVM_MAGIC_FEAT_SR		(1 << 0)
+
+/* MASn, ESR, PIR, and high SPRGs */
+#define KVM_MAGIC_FEAT_MAS0_TO_SPRG7	(1 << 1)
 
 
 #endif /* __POWERPC_KVM_PARA_H__ */
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
index 82b32a1..9acbde4 100644
--- a/linux-headers/asm-s390/kvm.h
+++ b/linux-headers/asm-s390/kvm.h
@@ -41,4 +41,13 @@ struct kvm_debug_exit_arch {
 struct kvm_guest_debug_arch {
 };
 
+#define KVM_SYNC_PREFIX (1UL << 0)
+#define KVM_SYNC_GPRS   (1UL << 1)
+#define KVM_SYNC_ACRS   (1UL << 2)
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+	__u64 prefix;	/* prefix register */
+	__u64 gprs[16];	/* general purpose registers */
+	__u32 acrs[16];	/* access registers */
+};
 #endif
diff --git a/linux-headers/asm-x86/hyperv.h b/linux-headers/asm-x86/hyperv.h
index 5df477a..b80420b 100644
--- a/linux-headers/asm-x86/hyperv.h
+++ b/linux-headers/asm-x86/hyperv.h
@@ -189,5 +189,6 @@
 #define HV_STATUS_INVALID_HYPERCALL_CODE	2
 #define HV_STATUS_INVALID_HYPERCALL_INPUT	3
 #define HV_STATUS_INVALID_ALIGNMENT		4
+#define HV_STATUS_INSUFFICIENT_BUFFERS		19
 
 #endif
diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
index 4d8dcbd..e7d1c19 100644
--- a/linux-headers/asm-x86/kvm.h
+++ b/linux-headers/asm-x86/kvm.h
@@ -321,4 +321,8 @@ struct kvm_xcrs {
 	__u64 padding[16];
 };
 
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+};
+
 #endif /* _ASM_X86_KVM_H */
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index a8761d3..4847813 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -162,6 +162,7 @@ struct kvm_pit_config {
 #define KVM_EXIT_INTERNAL_ERROR   17
 #define KVM_EXIT_OSI              18
 #define KVM_EXIT_PAPR_HCALL	  19
+#define KVM_EXIT_S390_UCONTROL	  20
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 #define KVM_INTERNAL_ERROR_EMULATION 1
@@ -249,6 +250,11 @@ struct kvm_run {
 #define KVM_S390_RESET_CPU_INIT  8
 #define KVM_S390_RESET_IPL       16
 		__u64 s390_reset_flags;
+		/* KVM_EXIT_S390_UCONTROL */
+		struct {
+			__u64 trans_exc_code;
+			__u32 pgm_code;
+		} s390_ucontrol;
 		/* KVM_EXIT_DCR */
 		struct {
 			__u32 dcrn;
@@ -273,6 +279,20 @@ struct kvm_run {
 		/* Fix the size of the union. */
 		char padding[256];
 	};
+
+	/*
+	 * shared registers between kvm and userspace.
+	 * kvm_valid_regs specifies the register classes set by the host
+	 * kvm_dirty_regs specified the register classes dirtied by userspace
+	 * struct kvm_sync_regs is architecture specific, as well as the
+	 * bits for kvm_valid_regs and kvm_dirty_regs
+	 */
+	__u64 kvm_valid_regs;
+	__u64 kvm_dirty_regs;
+	union {
+		struct kvm_sync_regs regs;
+		char padding[1024];
+	} s;
 };
 
 /* for KVM_REGISTER_COALESCED_MMIO / KVM_UNREGISTER_COALESCED_MMIO */
@@ -371,6 +391,7 @@ struct kvm_s390_psw {
 #define KVM_S390_INT_VIRTIO		0xffff2603u
 #define KVM_S390_INT_SERVICE		0xffff2401u
 #define KVM_S390_INT_EMERGENCY		0xffff1201u
+#define KVM_S390_INT_EXTERNAL_CALL	0xffff1202u
 
 struct kvm_s390_interrupt {
 	__u32 type;
@@ -430,6 +451,11 @@ struct kvm_ppc_pvinfo {
 
 #define KVMIO 0xAE
 
+/* machine type bits, to be used as argument to KVM_CREATE_VM */
+#define KVM_VM_S390_UCONTROL	1
+
+#define KVM_S390_SIE_PAGE_OFFSET 1
+
 /*
  * ioctls for /dev/kvm fds:
  */
@@ -558,6 +584,10 @@ struct kvm_ppc_pvinfo {
 #define KVM_CAP_PPC_PAPR 68
 #define KVM_CAP_SW_TLB 69
 #define KVM_CAP_ONE_REG 70
+#define KVM_CAP_S390_GMAP 71
+#define KVM_CAP_TSC_DEADLINE_TIMER 72
+#define KVM_CAP_S390_UCONTROL 73
+#define KVM_CAP_SYNC_REGS 74
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -698,6 +728,17 @@ struct kvm_one_reg {
 					struct kvm_userspace_memory_region)
 #define KVM_SET_TSS_ADDR          _IO(KVMIO,   0x47)
 #define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO,  0x48, __u64)
+
+/* enable ucontrol for s390 */
+struct kvm_s390_ucas_mapping {
+	__u64 user_addr;
+	__u64 vcpu_addr;
+	__u64 length;
+};
+#define KVM_S390_UCAS_MAP        _IOW(KVMIO, 0x50, struct kvm_s390_ucas_mapping)
+#define KVM_S390_UCAS_UNMAP      _IOW(KVMIO, 0x51, struct kvm_s390_ucas_mapping)
+#define KVM_S390_VCPU_FAULT	 _IOW(KVMIO, 0x52, unsigned long)
+
 /* Device model IOC */
 #define KVM_CREATE_IRQCHIP        _IO(KVMIO,   0x60)
 #define KVM_IRQ_LINE              _IOW(KVMIO,  0x61, struct kvm_irq_level)
diff --git a/linux-headers/linux/kvm_para.h b/linux-headers/linux/kvm_para.h
index b315e27..7bdcf93 100644
--- a/linux-headers/linux/kvm_para.h
+++ b/linux-headers/linux/kvm_para.h
@@ -26,4 +26,3 @@
 #include <asm/kvm_para.h>
 
 #endif /* __LINUX_KVM_PARA_H */
-
diff --git a/linux-headers/linux/virtio_ring.h b/linux-headers/linux/virtio_ring.h
index 78289ee..1b333e2 100644
--- a/linux-headers/linux/virtio_ring.h
+++ b/linux-headers/linux/virtio_ring.h
@@ -135,13 +135,13 @@ static __inline__ void vring_init(struct vring *vr, unsigned int num, void *p,
 	vr->num = num;
 	vr->desc = p;
 	vr->avail = p + num*sizeof(struct vring_desc);
-	vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + align-1)
-			    & ~(align - 1));
+	vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + sizeof(__u16)
+		+ align-1) & ~(align - 1));
 }
 
 static __inline__ unsigned vring_size(unsigned int num, unsigned long align)
 {
-	return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (2 + num)
+	return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (3 + num)
 		 + align - 1) & ~(align - 1))
 		+ sizeof(__u16) * 3 + sizeof(struct vring_used_elem) * num;
 }
commit 4c32fe66b936fd024e194127bda27b264d1f7e5c
Author: Stefan Weil <sw at weilnetz.de>
Date:   Fri Jan 27 17:40:43 2012 +0100

    Change license from GPLv2 to GPLv2+
    
    This file only contains code from Red Hat, so it can use GPLv2+.
    Tested with `git blame -M -C net/checksum.c`.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/net/checksum.c b/net/checksum.c
index 264c23f..9919b2e 100644
--- a/net/checksum.c
+++ b/net/checksum.c
@@ -4,7 +4,7 @@
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; under version 2 of the License.
+ *  the Free Software Foundation; under version 2 or later of the License.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,9 +13,6 @@
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *  Contributions after 2012-01-13 are licensed under the terms of the
- *  GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "net/checksum.h"
commit a7c36ee4920ea3acc227a0248dd161693f207357
Author: Corey Bryant <coreyb at linux.vnet.ibm.com>
Date:   Thu Jan 26 09:42:27 2012 -0500

    Add support for net bridge
    
    The most common use of -net tap is to connect a tap device to a bridge.  This
    requires the use of a script and running qemu as root in order to allocate a
    tap device to pass to the script.
    
    This model is great for portability and flexibility but it's incredibly
    difficult to eliminate the need to run qemu as root.  The only really viable
    mechanism is to use tunctl to create a tap device, attach it to a bridge as
    root, and then hand that tap device to qemu.  The problem with this mechanism
    is that it requires administrator intervention whenever a user wants to create
    a guest.
    
    By essentially writing a helper that implements the most common qemu-ifup
    script that can be safely given cap_net_admin, we can dramatically simplify
    things for non-privileged users.  We still support existing -net tap options
    as a mechanism for advanced users and backwards compatibility.
    
    Currently, this is very Linux centric but there's really no reason why it
    couldn't be extended for other Unixes.
    
    A typical invocation would be similar to one of the following:
    
      qemu linux.img -net bridge -net nic,model=virtio
    
      qemu linux.img -net tap,helper="/usr/local/libexec/qemu-bridge-helper"
                     -net nic,model=virtio
    
      qemu linux.img -netdev bridge,id=hn0
                     -device virtio-net-pci,netdev=hn0,id=nic1
    
      qemu linux.img -netdev tap,helper="/usr/local/libexec/qemu-bridge-helper",id=hn0
                     -device virtio-net-pci,netdev=hn0,id=nic1
    
    The default bridge that we attach to is br0.  The thinking is that a distro
    could preconfigure such an interface to allow out-of-the-box bridged networking.
    
    Alternatively, if a user wants to use a different bridge, a typical invocation
    would be simliar to one of the following:
    
      qemu linux.img -net bridge,br=qemubr0 -net nic,model=virtio
    
      qemu linux.img -net tap,helper="/usr/local/libexec/qemu-bridge-helper --br=qemubr0"
                     -net nic,model=virtio
    
      qemu linux.img -netdev bridge,br=qemubr0,id=hn0
                     -device virtio-net-pci,netdev=hn0,id=nic1
    
      qemu linux.img -netdev tap,helper="/usr/local/libexec/qemu-bridge-helper --br=qemubr0",id=hn0
                     -device virtio-net-pci,netdev=hn0,id=nic1
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Richa Marwaha <rmarwah at linux.vnet.ibm.com>
    Signed-off-by: Corey Bryant <coreyb at linux.vnet.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index 9f2a7e1..763db24 100755
--- a/configure
+++ b/configure
@@ -2942,6 +2942,8 @@ echo "sysconfdir=$sysconfdir" >> $config_host_mak
 echo "docdir=$docdir" >> $config_host_mak
 echo "confdir=$confdir" >> $config_host_mak
 echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
+echo "CONFIG_QEMU_SHAREDIR=\"$prefix$datasuffix\"" >> $config_host_mak
+echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak
 
 echo "ARCH=$ARCH" >> $config_host_mak
 if test "$debug_tcg" = "yes" ; then
diff --git a/net.c b/net.c
index 2b0f766..1944539 100644
--- a/net.c
+++ b/net.c
@@ -952,6 +952,10 @@ static const struct {
                 .type = QEMU_OPT_STRING,
                 .help = "script to shut down the interface",
             }, {
+                .name = "helper",
+                .type = QEMU_OPT_STRING,
+                .help = "command to execute to configure bridge",
+            }, {
                 .name = "sndbuf",
                 .type = QEMU_OPT_SIZE,
                 .help = "send buffer limit"
@@ -1053,6 +1057,23 @@ static const struct {
             { /* end of list */ }
         },
     },
+    [NET_CLIENT_TYPE_BRIDGE] = {
+        .type = "bridge",
+        .init = net_init_bridge,
+        .desc = {
+            NET_COMMON_PARAMS_DESC,
+            {
+                .name = "br",
+                .type = QEMU_OPT_STRING,
+                .help = "bridge name",
+            }, {
+                .name = "helper",
+                .type = QEMU_OPT_STRING,
+                .help = "command to execute to configure bridge",
+            },
+            { /* end of list */ }
+        },
+    },
 };
 
 int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
@@ -1075,7 +1096,8 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
 #ifdef CONFIG_VDE
             strcmp(type, "vde") != 0 &&
 #endif
-            strcmp(type, "socket") != 0) {
+            strcmp(type, "socket") != 0 &&
+            strcmp(type, "bridge") != 0) {
             qerror_report(QERR_INVALID_PARAMETER_VALUE, "type",
                           "a netdev backend type");
             return -1;
@@ -1145,6 +1167,7 @@ static int net_host_check_device(const char *device)
 #ifdef CONFIG_VDE
                                        ,"vde"
 #endif
+                                       , "bridge"
     };
     for (i = 0; i < sizeof(valid_param_list) / sizeof(char *); i++) {
         if (!strncmp(valid_param_list[i], device,
diff --git a/net.h b/net.h
index eab089d..75a8c15 100644
--- a/net.h
+++ b/net.h
@@ -37,6 +37,7 @@ typedef enum {
     NET_CLIENT_TYPE_SOCKET,
     NET_CLIENT_TYPE_VDE,
     NET_CLIENT_TYPE_DUMP,
+    NET_CLIENT_TYPE_BRIDGE,
 
     NET_CLIENT_TYPE_MAX
 } net_client_type;
@@ -174,6 +175,8 @@ int do_netdev_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
 
 #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
 #define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
+#define DEFAULT_BRIDGE_HELPER CONFIG_QEMU_HELPERDIR "/qemu-bridge-helper"
+#define DEFAULT_BRIDGE_INTERFACE "br0"
 
 void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd);
 
diff --git a/net/tap.c b/net/tap.c
index 6c27a94..f240028 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -382,6 +382,171 @@ static int launch_script(const char *setup_script, const char *ifname, int fd)
     return -1;
 }
 
+static int recv_fd(int c)
+{
+    int fd;
+    uint8_t msgbuf[CMSG_SPACE(sizeof(fd))];
+    struct msghdr msg = {
+        .msg_control = msgbuf,
+        .msg_controllen = sizeof(msgbuf),
+    };
+    struct cmsghdr *cmsg;
+    struct iovec iov;
+    uint8_t req[1];
+    ssize_t len;
+
+    cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_level = SOL_SOCKET;
+    cmsg->cmsg_type = SCM_RIGHTS;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+    msg.msg_controllen = cmsg->cmsg_len;
+
+    iov.iov_base = req;
+    iov.iov_len = sizeof(req);
+
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+
+    len = recvmsg(c, &msg, 0);
+    if (len > 0) {
+        memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd));
+        return fd;
+    }
+
+    return len;
+}
+
+static int net_bridge_run_helper(const char *helper, const char *bridge)
+{
+    sigset_t oldmask, mask;
+    int pid, status;
+    char *args[5];
+    char **parg;
+    int sv[2];
+
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGCHLD);
+    sigprocmask(SIG_BLOCK, &mask, &oldmask);
+
+    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
+        return -1;
+    }
+
+    /* try to launch bridge helper */
+    pid = fork();
+    if (pid == 0) {
+        int open_max = sysconf(_SC_OPEN_MAX), i;
+        char fd_buf[6+10];
+        char br_buf[6+IFNAMSIZ] = {0};
+        char helper_cmd[PATH_MAX + sizeof(fd_buf) + sizeof(br_buf) + 15];
+
+        for (i = 0; i < open_max; i++) {
+            if (i != STDIN_FILENO &&
+                i != STDOUT_FILENO &&
+                i != STDERR_FILENO &&
+                i != sv[1]) {
+                close(i);
+            }
+        }
+
+        snprintf(fd_buf, sizeof(fd_buf), "%s%d", "--fd=", sv[1]);
+
+        if (strrchr(helper, ' ') || strrchr(helper, '\t')) {
+            /* assume helper is a command */
+
+            if (strstr(helper, "--br=") == NULL) {
+                snprintf(br_buf, sizeof(br_buf), "%s%s", "--br=", bridge);
+            }
+
+            snprintf(helper_cmd, sizeof(helper_cmd), "%s %s %s %s",
+                     helper, "--use-vnet", fd_buf, br_buf);
+
+            parg = args;
+            *parg++ = (char *)"sh";
+            *parg++ = (char *)"-c";
+            *parg++ = helper_cmd;
+            *parg++ = NULL;
+
+            execv("/bin/sh", args);
+        } else {
+            /* assume helper is just the executable path name */
+
+            snprintf(br_buf, sizeof(br_buf), "%s%s", "--br=", bridge);
+
+            parg = args;
+            *parg++ = (char *)helper;
+            *parg++ = (char *)"--use-vnet";
+            *parg++ = fd_buf;
+            *parg++ = br_buf;
+            *parg++ = NULL;
+
+            execv(helper, args);
+        }
+        _exit(1);
+
+    } else if (pid > 0) {
+        int fd;
+
+        close(sv[1]);
+
+        do {
+            fd = recv_fd(sv[0]);
+        } while (fd == -1 && errno == EINTR);
+
+        close(sv[0]);
+
+        while (waitpid(pid, &status, 0) != pid) {
+            /* loop */
+        }
+        sigprocmask(SIG_SETMASK, &oldmask, NULL);
+        if (fd < 0) {
+            fprintf(stderr, "failed to recv file descriptor\n");
+            return -1;
+        }
+
+        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+            return fd;
+        }
+    }
+    fprintf(stderr, "failed to launch bridge helper\n");
+    return -1;
+}
+
+int net_init_bridge(QemuOpts *opts, Monitor *mon, const char *name,
+                    VLANState *vlan)
+{
+    TAPState *s;
+    int fd, vnet_hdr;
+
+    if (!qemu_opt_get(opts, "br")) {
+        qemu_opt_set(opts, "br", DEFAULT_BRIDGE_INTERFACE);
+    }
+    if (!qemu_opt_get(opts, "helper")) {
+        qemu_opt_set(opts, "helper", DEFAULT_BRIDGE_HELPER);
+    }
+
+    fd = net_bridge_run_helper(qemu_opt_get(opts, "helper"),
+                               qemu_opt_get(opts, "br"));
+    if (fd == -1) {
+        return -1;
+    }
+
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+
+    vnet_hdr = tap_probe_vnet_hdr(fd);
+
+    s = net_tap_fd_init(vlan, "bridge", name, fd, vnet_hdr);
+    if (!s) {
+        close(fd);
+        return -1;
+    }
+
+    snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s,br=%s",
+             qemu_opt_get(opts, "helper"), qemu_opt_get(opts, "br"));
+
+    return 0;
+}
+
 static int net_tap_init(QemuOpts *opts, int *vnet_hdr)
 {
     int fd, vnet_hdr_required;
@@ -422,13 +587,16 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
 {
     TAPState *s;
     int fd, vnet_hdr = 0;
+    const char *model;
 
     if (qemu_opt_get(opts, "fd")) {
         if (qemu_opt_get(opts, "ifname") ||
             qemu_opt_get(opts, "script") ||
             qemu_opt_get(opts, "downscript") ||
-            qemu_opt_get(opts, "vnet_hdr")) {
-            error_report("ifname=, script=, downscript= and vnet_hdr= is invalid with fd=");
+            qemu_opt_get(opts, "vnet_hdr") ||
+            qemu_opt_get(opts, "helper")) {
+            error_report("ifname=, script=, downscript=, vnet_hdr=, "
+                         "and helper= are invalid with fd=");
             return -1;
         }
 
@@ -440,6 +608,31 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
         fcntl(fd, F_SETFL, O_NONBLOCK);
 
         vnet_hdr = tap_probe_vnet_hdr(fd);
+
+        model = "tap";
+
+    } else if (qemu_opt_get(opts, "helper")) {
+        if (qemu_opt_get(opts, "ifname") ||
+            qemu_opt_get(opts, "script") ||
+            qemu_opt_get(opts, "downscript") ||
+            qemu_opt_get(opts, "vnet_hdr")) {
+            error_report("ifname=, script=, downscript=, and vnet_hdr= "
+                         "are invalid with helper=");
+            return -1;
+        }
+
+        fd = net_bridge_run_helper(qemu_opt_get(opts, "helper"),
+                                   DEFAULT_BRIDGE_INTERFACE);
+        if (fd == -1) {
+            return -1;
+        }
+
+        fcntl(fd, F_SETFL, O_NONBLOCK);
+
+        vnet_hdr = tap_probe_vnet_hdr(fd);
+
+        model = "bridge";
+
     } else {
         if (!qemu_opt_get(opts, "script")) {
             qemu_opt_set(opts, "script", DEFAULT_NETWORK_SCRIPT);
@@ -453,9 +646,11 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
         if (fd == -1) {
             return -1;
         }
+
+        model = "tap";
     }
 
-    s = net_tap_fd_init(vlan, "tap", name, fd, vnet_hdr);
+    s = net_tap_fd_init(vlan, model, name, fd, vnet_hdr);
     if (!s) {
         close(fd);
         return -1;
@@ -467,6 +662,9 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
 
     if (qemu_opt_get(opts, "fd")) {
         snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd);
+    } else if (qemu_opt_get(opts, "helper")) {
+        snprintf(s->nc.info_str, sizeof(s->nc.info_str),
+                 "helper=%s", qemu_opt_get(opts, "helper"));
     } else {
         const char *ifname, *script, *downscript;
 
diff --git a/net/tap.h b/net/tap.h
index e44bd2b..56c591f 100644
--- a/net/tap.h
+++ b/net/tap.h
@@ -57,4 +57,7 @@ int tap_get_fd(VLANClientState *vc);
 struct vhost_net;
 struct vhost_net *tap_get_vhost_net(VLANClientState *vc);
 
+int net_init_bridge(QemuOpts *opts, Monitor *mon, const char *name,
+                    VLANState *vlan);
+
 #endif /* QEMU_NET_TAP_H */
diff --git a/qemu-options.hx b/qemu-options.hx
index 3a07ae8..19906e5 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1222,11 +1222,14 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
     "-net tap[,vlan=n][,name=str],ifname=name\n"
     "                connect the host TAP network interface to VLAN 'n'\n"
 #else
-    "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]\n"
-    "                connect the host TAP network interface to VLAN 'n' and use the\n"
-    "                network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n"
-    "                and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n"
+    "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]\n"
+    "                connect the host TAP network interface to VLAN 'n' \n"
+    "                use network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n"
+    "                to configure it and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n"
+    "                to deconfigure it\n"
     "                use '[down]script=no' to disable script execution\n"
+    "                use network helper 'helper' (default=" DEFAULT_BRIDGE_HELPER ") to\n"
+    "                configure it\n"
     "                use 'fd=h' to connect to an already opened TAP interface\n"
     "                use 'sndbuf=nbytes' to limit the size of the send buffer (the\n"
     "                default is disabled 'sndbuf=0' to enable flow control set 'sndbuf=1048576')\n"
@@ -1236,6 +1239,10 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
     "                    (only has effect for virtio guests which use MSIX)\n"
     "                use vhostforce=on to force vhost on for non-MSIX virtio guests\n"
     "                use 'vhostfd=h' to connect to an already opened vhost net device\n"
+    "-net bridge[,vlan=n][,name=str][,br=bridge][,helper=helper]\n"
+    "                connects a host TAP network interface to a host bridge device 'br'\n"
+    "                (default=" DEFAULT_BRIDGE_INTERFACE ") using the program 'helper'\n"
+    "                (default=" DEFAULT_BRIDGE_HELPER ")\n"
 #endif
     "-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n"
     "                connect the vlan 'n' to another VLAN using a socket connection\n"
@@ -1261,6 +1268,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
     "user|"
 #endif
     "tap|"
+    "bridge|"
 #ifdef CONFIG_VDE
     "vde|"
 #endif
@@ -1397,26 +1405,65 @@ processed and applied to -net user. Mixing them with the new configuration
 syntax gives undefined results. Their use for new applications is discouraged
 as they will be removed from future versions.
 
- at item -net tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}] [,script=@var{file}][,downscript=@var{dfile}]
-Connect the host TAP network interface @var{name} to VLAN @var{n}, use
-the network script @var{file} to configure it and the network script
+ at item -net tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}][,helper=@var{helper}]
+Connect the host TAP network interface @var{name} to VLAN @var{n}.
+
+Use the network script @var{file} to configure it and the network script
 @var{dfile} to deconfigure it. If @var{name} is not provided, the OS
-automatically provides one. @option{fd}=@var{h} can be used to specify
-the handle of an already opened host TAP interface. The default network
-configure script is @file{/etc/qemu-ifup} and the default network
-deconfigure script is @file{/etc/qemu-ifdown}. Use @option{script=no}
-or @option{downscript=no} to disable script execution. Example:
+automatically provides one. The default network configure script is
+ at file{/etc/qemu-ifup} and the default network deconfigure script is
+ at file{/etc/qemu-ifdown}. Use @option{script=no} or @option{downscript=no}
+to disable script execution.
+
+If running QEMU as an unprivileged user, use the network helper
+ at var{helper} to configure the TAP interface. The default network
+helper executable is @file{/usr/local/libexec/qemu-bridge-helper}.
+
+ at option{fd}=@var{h} can be used to specify the handle of an already
+opened host TAP interface.
+
+Examples:
 
 @example
+#launch a QEMU instance with the default network script
 qemu linux.img -net nic -net tap
 @end example
 
-More complicated example (two NICs, each one connected to a TAP device)
 @example
+#launch a QEMU instance with two NICs, each one connected
+#to a TAP device
 qemu linux.img -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
                -net nic,vlan=1 -net tap,vlan=1,ifname=tap1
 @end example
 
+ at example
+#launch a QEMU instance with the default network helper to
+#connect a TAP device to bridge br0
+qemu linux.img -net nic -net tap,"helper=/usr/local/libexec/qemu-bridge-helper"
+ at end example
+
+ at item -net bridge[,vlan=@var{n}][,name=@var{name}][,br=@var{bridge}][,helper=@var{helper}]
+Connect a host TAP network interface to a host bridge device.
+
+Use the network helper @var{helper} to configure the TAP interface and
+attach it to the bridge. The default network helper executable is
+ at file{/usr/local/libexec/qemu-bridge-helper} and the default bridge
+device is @file{br0}.
+
+Examples:
+
+ at example
+#launch a QEMU instance with the default network helper to
+#connect a TAP device to bridge br0
+qemu linux.img -net bridge -net nic,model=virtio
+ at end example
+
+ at example
+#launch a QEMU instance with the default network helper to
+#connect a TAP device to bridge qemubr0
+qemu linux.img -net bridge,br=qemubr0 -net nic,model=virtio
+ at end example
+
 @item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}] [,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}]
 
 Connect the VLAN @var{n} to a remote VLAN in another QEMU virtual
commit 47e98658f58b8afd319851f44edcb81f2d2d3774
Author: Corey Bryant <coreyb at linux.vnet.ibm.com>
Date:   Thu Jan 26 09:42:26 2012 -0500

    Add cap reduction support to enable use as SUID
    
    The ideal way to use qemu-bridge-helper is to give it an fscap of using:
    
     setcap cap_net_admin=ep qemu-bridge-helper
    
    Unfortunately, most distros still do not have a mechanism to package files
    with fscaps applied.  This means they'll have to SUID the qemu-bridge-helper
    binary.
    
    To improve security, use libcap to reduce our capability set to just
    cap_net_admin, then reduce privileges down to the calling user.  This is
    hopefully close to equivalent to fscap support from a security perspective.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Richa Marwaha <rmarwah at linux.vnet.ibm.com>
    Signed-off-by: Corey Bryant <coreyb at linux.vnet.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index b7e5ca6..9f2a7e1 100755
--- a/configure
+++ b/configure
@@ -133,6 +133,7 @@ vnc_thread="no"
 xen=""
 xen_ctrl_version=""
 linux_aio=""
+cap_ng=""
 attr=""
 libattr=""
 xfs=""
@@ -672,6 +673,10 @@ for opt do
   ;;
   --enable-tcg-interpreter) tcg_interpreter="yes"
   ;;
+  --disable-cap-ng)  cap_ng="no"
+  ;;
+  --enable-cap-ng) cap_ng="yes"
+  ;;
   --disable-spice) spice="no"
   ;;
   --enable-spice) spice="yes"
@@ -1053,6 +1058,8 @@ echo "  --disable-vde            disable support for vde network"
 echo "  --enable-vde             enable support for vde network"
 echo "  --disable-linux-aio      disable Linux AIO support"
 echo "  --enable-linux-aio       enable Linux AIO support"
+echo "  --disable-cap-ng         disable libcap-ng support"
+echo "  --enable-cap-ng          enable libcap-ng support"
 echo "  --disable-attr           disables attr and xattr support"
 echo "  --enable-attr            enable attr and xattr support"
 echo "  --disable-blobs          disable installing provided firmware blobs"
@@ -1745,6 +1752,29 @@ EOF
 fi
 
 ##########################################
+# libcap-ng library probe
+if test "$cap_ng" != "no" ; then
+  cap_libs="-lcap-ng"
+  cat > $TMPC << EOF
+#include <cap-ng.h>
+int main(void)
+{
+    capng_capability_to_name(CAPNG_EFFECTIVE);
+    return 0;
+}
+EOF
+  if compile_prog "" "$cap_libs" ; then
+    cap_ng=yes
+    libs_tools="$cap_libs $libs_tools"
+  else
+    if test "$cap_ng" = "yes" ; then
+      feature_not_found "cap_ng"
+    fi
+    cap_ng=no
+  fi
+fi
+
+##########################################
 # Sound support libraries probe
 
 audio_drv_probe()
@@ -2876,6 +2906,7 @@ echo "fdatasync         $fdatasync"
 echo "madvise           $madvise"
 echo "posix_madvise     $posix_madvise"
 echo "uuid support      $uuid"
+echo "libcap-ng support $cap_ng"
 echo "vhost-net support $vhost_net"
 echo "Trace backend     $trace_backend"
 echo "Trace output file $trace_file-<pid>"
@@ -2980,6 +3011,9 @@ fi
 if test "$vde" = "yes" ; then
   echo "CONFIG_VDE=y" >> $config_host_mak
 fi
+if test "$cap_ng" = "yes" ; then
+  echo "CONFIG_LIBCAP=y" >> $config_host_mak
+fi
 for card in $audio_card_list; do
     def=CONFIG_`echo $card | tr '[:lower:]' '[:upper:]'`
     echo "$def=y" >> $config_host_mak
diff --git a/qemu-bridge-helper.c b/qemu-bridge-helper.c
index 01eeb38..aec5008 100644
--- a/qemu-bridge-helper.c
+++ b/qemu-bridge-helper.c
@@ -39,6 +39,10 @@
 
 #include "net/tap-linux.h"
 
+#ifdef CONFIG_LIBCAP
+#include <cap-ng.h>
+#endif
+
 #define DEFAULT_ACL_FILE CONFIG_QEMU_CONFDIR "/bridge.conf"
 
 enum {
@@ -193,6 +197,27 @@ static int send_fd(int c, int fd)
     return sendmsg(c, &msg, 0);
 }
 
+#ifdef CONFIG_LIBCAP
+static int drop_privileges(void)
+{
+    /* clear all capabilities */
+    capng_clear(CAPNG_SELECT_BOTH);
+
+    if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
+                     CAP_NET_ADMIN) < 0) {
+        return -1;
+    }
+
+    /* change to calling user's real uid and gid, retaining supplemental
+     * groups and CAP_NET_ADMIN */
+    if (capng_change_id(getuid(), getgid(), CAPNG_CLEAR_BOUNDING)) {
+        return -1;
+    }
+
+    return 0;
+}
+#endif
+
 int main(int argc, char **argv)
 {
     struct ifreq ifr;
@@ -207,6 +232,17 @@ int main(int argc, char **argv)
     int access_allowed, access_denied;
     int ret = EXIT_SUCCESS;
 
+#ifdef CONFIG_LIBCAP
+    /* if we're run from an suid binary, immediately drop privileges preserving
+     * cap_net_admin */
+    if (geteuid() == 0 && getuid() != geteuid()) {
+        if (drop_privileges() == -1) {
+            fprintf(stderr, "failed to drop privileges\n");
+            return 1;
+        }
+    }
+#endif
+
     /* parse arguments */
     for (index = 1; index < argc; index++) {
         if (strcmp(argv[index], "--use-vnet") == 0) {
commit bdef79a2994d6f0383e07e9597675711662b3031
Author: Corey Bryant <coreyb at linux.vnet.ibm.com>
Date:   Thu Jan 26 09:42:25 2012 -0500

    Add access control support to qemu bridge helper
    
    We go to great lengths to restrict ourselves to just cap_net_admin as an OS
    enforced security mechanism.  However, we further restrict what we allow users
    to do to simply adding a tap device to a bridge interface by virtue of the fact
    that this is the only functionality we expose.
    
    This is not good enough though.  An administrator is likely to want to restrict
    the bridges that an unprivileged user can access, in particular, to restrict
    an unprivileged user from putting a guest on what should be isolated networks.
    
    This patch implements an ACL mechanism that is enforced by qemu-bridge-helper.
    The ACLs are fairly simple whitelist/blacklist mechanisms with a wildcard of
    'all'.  All users are blacklisted by default, and deny takes precedence over
    allow.
    
    An interesting feature of this ACL mechanism is that you can include external
    ACL files.  The main reason to support this is so that you can set different
    file system permissions on those external ACL files.  This allows an
    administrator to implement rather sophisticated ACL policies based on
    user/group policies via the file system.
    
    As an example:
    
    /etc/qemu/bridge.conf root:qemu 0640
    
     allow br0
     include /etc/qemu/alice.conf
     include /etc/qemu/bob.conf
     include /etc/qemu/charlie.conf
    
    /etc/qemu/alice.conf root:alice 0640
     allow br1
    
    /etc/qemu/bob.conf root:bob 0640
     allow br2
    
    /etc/qemu/charlie.conf root:charlie 0640
     deny all
    
    This ACL pattern allows any user in the qemu group to get a tap device
    connected to br0 (which is bridged to the physical network).
    
    Users in the alice group can additionally get a tap device connected to br1.
    This allows br1 to act as a private bridge for the alice group.
    
    Users in the bob group can additionally get a tap device connected to br2.
    This allows br2 to act as a private bridge for the bob group.
    
    Users in the charlie group cannot get a tap device connected to any bridge.
    
    Under no circumstance can the bob group get access to br1 or can the alice
    group get access to br2.  And under no cicumstance can the charlie group
    get access to any bridge.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Richa Marwaha <rmarwah at linux.vnet.ibm.com>
    Signed-off-by: Corey Bryant <coreyb at linux.vnet.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/qemu-bridge-helper.c b/qemu-bridge-helper.c
index 48c5e22..01eeb38 100644
--- a/qemu-bridge-helper.c
+++ b/qemu-bridge-helper.c
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <stdbool.h>
 #include <ctype.h>
+#include <glib.h>
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
@@ -34,14 +35,116 @@
 
 #include <linux/sockios.h>
 
+#include "qemu-queue.h"
+
 #include "net/tap-linux.h"
 
+#define DEFAULT_ACL_FILE CONFIG_QEMU_CONFDIR "/bridge.conf"
+
+enum {
+    ACL_ALLOW = 0,
+    ACL_ALLOW_ALL,
+    ACL_DENY,
+    ACL_DENY_ALL,
+};
+
+typedef struct ACLRule {
+    int type;
+    char iface[IFNAMSIZ];
+    QSIMPLEQ_ENTRY(ACLRule) entry;
+} ACLRule;
+
+typedef QSIMPLEQ_HEAD(ACLList, ACLRule) ACLList;
+
 static void usage(void)
 {
     fprintf(stderr,
             "Usage: qemu-bridge-helper [--use-vnet] --br=bridge --fd=unixfd\n");
 }
 
+static int parse_acl_file(const char *filename, ACLList *acl_list)
+{
+    FILE *f;
+    char line[4096];
+    ACLRule *acl_rule;
+
+    f = fopen(filename, "r");
+    if (f == NULL) {
+        return -1;
+    }
+
+    while (fgets(line, sizeof(line), f) != NULL) {
+        char *ptr = line;
+        char *cmd, *arg, *argend;
+
+        while (isspace(*ptr)) {
+            ptr++;
+        }
+
+        /* skip comments and empty lines */
+        if (*ptr == '#' || *ptr == 0) {
+            continue;
+        }
+
+        cmd = ptr;
+        arg = strchr(cmd, ' ');
+        if (arg == NULL) {
+            arg = strchr(cmd, '\t');
+        }
+
+        if (arg == NULL) {
+            fprintf(stderr, "Invalid config line:\n  %s\n", line);
+            fclose(f);
+            errno = EINVAL;
+            return -1;
+        }
+
+        *arg = 0;
+        arg++;
+        while (isspace(*arg)) {
+            arg++;
+        }
+
+        argend = arg + strlen(arg);
+        while (arg != argend && isspace(*(argend - 1))) {
+            argend--;
+        }
+        *argend = 0;
+
+        if (strcmp(cmd, "deny") == 0) {
+            acl_rule = g_malloc(sizeof(*acl_rule));
+            if (strcmp(arg, "all") == 0) {
+                acl_rule->type = ACL_DENY_ALL;
+            } else {
+                acl_rule->type = ACL_DENY;
+                snprintf(acl_rule->iface, IFNAMSIZ, "%s", arg);
+            }
+            QSIMPLEQ_INSERT_TAIL(acl_list, acl_rule, entry);
+        } else if (strcmp(cmd, "allow") == 0) {
+            acl_rule = g_malloc(sizeof(*acl_rule));
+            if (strcmp(arg, "all") == 0) {
+                acl_rule->type = ACL_ALLOW_ALL;
+            } else {
+                acl_rule->type = ACL_ALLOW;
+                snprintf(acl_rule->iface, IFNAMSIZ, "%s", arg);
+            }
+            QSIMPLEQ_INSERT_TAIL(acl_list, acl_rule, entry);
+        } else if (strcmp(cmd, "include") == 0) {
+            /* ignore errors */
+            parse_acl_file(arg, acl_list);
+        } else {
+            fprintf(stderr, "Unknown command `%s'\n", cmd);
+            fclose(f);
+            errno = EINVAL;
+            return -1;
+        }
+    }
+
+    fclose(f);
+
+    return 0;
+}
+
 static bool has_vnet_hdr(int fd)
 {
     unsigned int features = 0;
@@ -99,6 +202,9 @@ int main(int argc, char **argv)
     const char *bridge = NULL;
     char iface[IFNAMSIZ];
     int index;
+    ACLRule *acl_rule;
+    ACLList acl_list;
+    int access_allowed, access_denied;
     int ret = EXIT_SUCCESS;
 
     /* parse arguments */
@@ -120,6 +226,48 @@ int main(int argc, char **argv)
         return EXIT_FAILURE;
     }
 
+    /* parse default acl file */
+    QSIMPLEQ_INIT(&acl_list);
+    if (parse_acl_file(DEFAULT_ACL_FILE, &acl_list) == -1) {
+        fprintf(stderr, "failed to parse default acl file `%s'\n",
+                DEFAULT_ACL_FILE);
+        ret = EXIT_FAILURE;
+        goto cleanup;
+    }
+
+    /* validate bridge against acl -- default policy is to deny
+     * according acl policy if we have a deny and allow both
+     * then deny should always win over allow
+     */
+    access_allowed = 0;
+    access_denied = 0;
+    QSIMPLEQ_FOREACH(acl_rule, &acl_list, entry) {
+        switch (acl_rule->type) {
+        case ACL_ALLOW_ALL:
+            access_allowed = 1;
+            break;
+        case ACL_ALLOW:
+            if (strcmp(bridge, acl_rule->iface) == 0) {
+                access_allowed = 1;
+            }
+            break;
+        case ACL_DENY_ALL:
+            access_denied = 1;
+            break;
+        case ACL_DENY:
+            if (strcmp(bridge, acl_rule->iface) == 0) {
+                access_denied = 1;
+            }
+            break;
+        }
+    }
+
+    if ((access_allowed == 0) || (access_denied == 1)) {
+        fprintf(stderr, "access denied by acl file\n");
+        ret = EXIT_FAILURE;
+        goto cleanup;
+    }
+
     /* open a socket to use to control the network interfaces */
     ctlfd = socket(AF_INET, SOCK_STREAM, 0);
     if (ctlfd == -1) {
@@ -217,5 +365,10 @@ int main(int argc, char **argv)
 
 cleanup:
 
+    while ((acl_rule = QSIMPLEQ_FIRST(&acl_list)) != NULL) {
+        QSIMPLEQ_REMOVE_HEAD(&acl_list, entry);
+        g_free(acl_rule);
+    }
+
     return ret;
 }
commit 7b93fadf3a38d1ed65ea5536a52efc2772c6e3b8
Author: Corey Bryant <coreyb at linux.vnet.ibm.com>
Date:   Thu Jan 26 09:42:24 2012 -0500

    Add basic version of bridge helper
    
    This patch adds a helper that can be used to create a tap device attached to
    a bridge device.  Since this helper is minimal in what it does, it can be
    given CAP_NET_ADMIN which allows qemu to avoid running as root while still
    satisfying the majority of what users tend to want to do with tap devices.
    
    The way this all works is that qemu launches this helper passing a bridge
    name and the name of an inherited file descriptor.  The descriptor is one
    end of a socketpair() of domain sockets.  This domain socket is used to
    transmit a file descriptor of the opened tap device from the helper to qemu.
    
    The helper can then exit and let qemu use the tap device.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Richa Marwaha <rmarwah at linux.vnet.ibm.com>
    Signed-off-by: Corey Bryant <coreyb at linux.vnet.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/Makefile b/Makefile
index 2560b59..47acf3d 100644
--- a/Makefile
+++ b/Makefile
@@ -36,6 +36,8 @@ $(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw)
 
 LIBS+=-lz $(LIBS_TOOLS)
 
+HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
+
 ifdef BUILD_DOCS
 DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 QMP/qmp-commands.txt
 DOCS+=fsdev/virtfs-proxy-helper.1
@@ -77,7 +79,7 @@ defconfig:
 
 -include config-all-devices.mak
 
-build-all: $(DOCS) $(TOOLS) recurse-all
+build-all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all
 
 config-host.h: config-host.h-timestamp
 config-host.h-timestamp: config-host.mak
@@ -158,6 +160,8 @@ qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
 qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y)
 qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
 
+qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
+
 fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y)
 fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
 
@@ -207,7 +211,7 @@ clean:
 # avoid old build problems by removing potentially incorrect old files
 	rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
 	rm -f qemu-options.def
-	rm -f *.o *.d *.a *.lo $(TOOLS) qemu-ga TAGS cscope.* *.pod *~ */*~
+	rm -f *.o *.d *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
 	rm -Rf .libs
 	rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d qapi/*.o qapi/*.d qga/*.o qga/*.d
 	rm -f qemu-img-cmds.h
@@ -281,6 +285,10 @@ install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig
 ifneq ($(TOOLS),)
 	$(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
 endif
+ifneq ($(HELPERS-y),)
+	$(INSTALL_DIR) "$(DESTDIR)$(libexecdir)"
+	$(INSTALL_PROG) $(STRIP_OPT) $(HELPERS-y) "$(DESTDIR)$(libexecdir)"
+endif
 ifneq ($(BLOBS),)
 	$(INSTALL_DIR) "$(DESTDIR)$(datadir)"
 	set -e; for x in $(BLOBS); do \
diff --git a/configure b/configure
index 3b0b300..b7e5ca6 100755
--- a/configure
+++ b/configure
@@ -2910,6 +2910,7 @@ echo "datadir=$datadir" >> $config_host_mak
 echo "sysconfdir=$sysconfdir" >> $config_host_mak
 echo "docdir=$docdir" >> $config_host_mak
 echo "confdir=$confdir" >> $config_host_mak
+echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
 
 echo "ARCH=$ARCH" >> $config_host_mak
 if test "$debug_tcg" = "yes" ; then
diff --git a/qemu-bridge-helper.c b/qemu-bridge-helper.c
new file mode 100644
index 0000000..48c5e22
--- /dev/null
+++ b/qemu-bridge-helper.c
@@ -0,0 +1,221 @@
+/*
+ * QEMU Bridge Helper
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori   <aliguori at us.ibm.com>
+ * Richa Marwaha     <rmarwah at linux.vnet.ibm.com>
+ * Corey Bryant      <coreyb at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "config-host.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <ctype.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/prctl.h>
+
+#include <net/if.h>
+
+#include <linux/sockios.h>
+
+#include "net/tap-linux.h"
+
+static void usage(void)
+{
+    fprintf(stderr,
+            "Usage: qemu-bridge-helper [--use-vnet] --br=bridge --fd=unixfd\n");
+}
+
+static bool has_vnet_hdr(int fd)
+{
+    unsigned int features = 0;
+
+    if (ioctl(fd, TUNGETFEATURES, &features) == -1) {
+        return false;
+    }
+
+    if (!(features & IFF_VNET_HDR)) {
+        return false;
+    }
+
+    return true;
+}
+
+static void prep_ifreq(struct ifreq *ifr, const char *ifname)
+{
+    memset(ifr, 0, sizeof(*ifr));
+    snprintf(ifr->ifr_name, IFNAMSIZ, "%s", ifname);
+}
+
+static int send_fd(int c, int fd)
+{
+    char msgbuf[CMSG_SPACE(sizeof(fd))];
+    struct msghdr msg = {
+        .msg_control = msgbuf,
+        .msg_controllen = sizeof(msgbuf),
+    };
+    struct cmsghdr *cmsg;
+    struct iovec iov;
+    char req[1] = { 0x00 };
+
+    cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_level = SOL_SOCKET;
+    cmsg->cmsg_type = SCM_RIGHTS;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+    msg.msg_controllen = cmsg->cmsg_len;
+
+    iov.iov_base = req;
+    iov.iov_len = sizeof(req);
+
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
+
+    return sendmsg(c, &msg, 0);
+}
+
+int main(int argc, char **argv)
+{
+    struct ifreq ifr;
+    int fd, ctlfd, unixfd = -1;
+    int use_vnet = 0;
+    int mtu;
+    const char *bridge = NULL;
+    char iface[IFNAMSIZ];
+    int index;
+    int ret = EXIT_SUCCESS;
+
+    /* parse arguments */
+    for (index = 1; index < argc; index++) {
+        if (strcmp(argv[index], "--use-vnet") == 0) {
+            use_vnet = 1;
+        } else if (strncmp(argv[index], "--br=", 5) == 0) {
+            bridge = &argv[index][5];
+        } else if (strncmp(argv[index], "--fd=", 5) == 0) {
+            unixfd = atoi(&argv[index][5]);
+        } else {
+            usage();
+            return EXIT_FAILURE;
+        }
+    }
+
+    if (bridge == NULL || unixfd == -1) {
+        usage();
+        return EXIT_FAILURE;
+    }
+
+    /* open a socket to use to control the network interfaces */
+    ctlfd = socket(AF_INET, SOCK_STREAM, 0);
+    if (ctlfd == -1) {
+        fprintf(stderr, "failed to open control socket: %s\n", strerror(errno));
+        ret = EXIT_FAILURE;
+        goto cleanup;
+    }
+
+    /* open the tap device */
+    fd = open("/dev/net/tun", O_RDWR);
+    if (fd == -1) {
+        fprintf(stderr, "failed to open /dev/net/tun: %s\n", strerror(errno));
+        ret = EXIT_FAILURE;
+        goto cleanup;
+    }
+
+    /* request a tap device, disable PI, and add vnet header support if
+     * requested and it's available. */
+    prep_ifreq(&ifr, "tap%d");
+    ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
+    if (use_vnet && has_vnet_hdr(fd)) {
+        ifr.ifr_flags |= IFF_VNET_HDR;
+    }
+
+    if (ioctl(fd, TUNSETIFF, &ifr) == -1) {
+        fprintf(stderr, "failed to create tun device: %s\n", strerror(errno));
+        ret = EXIT_FAILURE;
+        goto cleanup;
+    }
+
+    /* save tap device name */
+    snprintf(iface, sizeof(iface), "%s", ifr.ifr_name);
+
+    /* get the mtu of the bridge */
+    prep_ifreq(&ifr, bridge);
+    if (ioctl(ctlfd, SIOCGIFMTU, &ifr) == -1) {
+        fprintf(stderr, "failed to get mtu of bridge `%s': %s\n",
+                bridge, strerror(errno));
+        ret = EXIT_FAILURE;
+        goto cleanup;
+    }
+
+    /* save mtu */
+    mtu = ifr.ifr_mtu;
+
+    /* set the mtu of the interface based on the bridge */
+    prep_ifreq(&ifr, iface);
+    ifr.ifr_mtu = mtu;
+    if (ioctl(ctlfd, SIOCSIFMTU, &ifr) == -1) {
+        fprintf(stderr, "failed to set mtu of device `%s' to %d: %s\n",
+                iface, mtu, strerror(errno));
+        ret = EXIT_FAILURE;
+        goto cleanup;
+    }
+
+    /* add the interface to the bridge */
+    prep_ifreq(&ifr, bridge);
+    ifr.ifr_ifindex = if_nametoindex(iface);
+
+    if (ioctl(ctlfd, SIOCBRADDIF, &ifr) == -1) {
+        fprintf(stderr, "failed to add interface `%s' to bridge `%s': %s\n",
+                iface, bridge, strerror(errno));
+        ret = EXIT_FAILURE;
+        goto cleanup;
+    }
+
+    /* bring the interface up */
+    prep_ifreq(&ifr, iface);
+    if (ioctl(ctlfd, SIOCGIFFLAGS, &ifr) == -1) {
+        fprintf(stderr, "failed to get interface flags for `%s': %s\n",
+                iface, strerror(errno));
+        ret = EXIT_FAILURE;
+        goto cleanup;
+    }
+
+    ifr.ifr_flags |= IFF_UP;
+    if (ioctl(ctlfd, SIOCSIFFLAGS, &ifr) == -1) {
+        fprintf(stderr, "failed to bring up interface `%s': %s\n",
+                iface, strerror(errno));
+        ret = EXIT_FAILURE;
+        goto cleanup;
+    }
+
+    /* write fd to the domain socket */
+    if (send_fd(unixfd, fd) == -1) {
+        fprintf(stderr, "failed to write fd to unix socket: %s\n",
+                strerror(errno));
+        ret = EXIT_FAILURE;
+        goto cleanup;
+    }
+
+    /* ... */
+
+    /* profit! */
+
+cleanup:
+
+    return ret;
+}
commit 069ab0eb8a46bc4ff6f4d4d81bf037d3441347da
Author: Gerhard Wiesinger <lists at wiesinger.com>
Date:   Wed Jan 25 21:04:14 2012 +0100

    hw/vmmouse.c: Disable vmmouse after reboot
    
    Bugfix after reboot when vmmouse was enabled and another OS which uses e.g. PS/2
    mouse.
    
    Details:
    When a guest activated the vmmouse followed by a reboot the vmmouse was still
    enabled and the PS/2 mouse was therefore unsusable. When another guest is then
    booted without vmmouse support (e.g. PS/2 mouse) the mouse is not working.
    
    Reason is that VMMouse has priority and disables all other mouse entities
    and therefore must be disabled on reset.
    
    Testscenario:
    1.) Boot e.g. OS with VMMouse support (e.g. Windows with VMMouse tools)
    2.) reboot
    3.) Boot e.g. OS without VMMouse support (e.g. DOS) => PS/2 mouse doesn't work
         any more. Fixes that issue.
    
    Testscenario 2 by Jan Kiszka <jan.kiszka at siemens.com>:
    Confirm that this patch fixes a real issue. Setup: qemu.git,
    opensuse 11.4 guest, SDL graphic, system_reset while guest is using the
    vmmouse. Without the patch, the vmmouse become unusable after the
    reboot. Also, the mouse stays in absolute mode even before X starts again.
    
    Fixed by:
    Disabling the vmmouse in its reset handler.
    
    Tested-by: Andreas F=E4rber <afaerber at suse.de>
    Signed-off-by: Gerhard Wiesinger <lists at wiesinger.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/vmmouse.c b/hw/vmmouse.c
index da2ea32..5c80bc4 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)
commit 93dd748b789202af4f5be75412c58ee1ed481b29
Author: Laszlo Ersek <lersek at redhat.com>
Date:   Fri Jan 27 14:34:05 2012 +0100

    keep the PID file locked for the lifetime of the process
    
    The lockf() call in qemu_create_pidfile() aims at ensuring mutual
    exclusion. We shouldn't close the pidfile on success (as introduced by
    commit 1bbd1592), because that drops the lock as well [1]:
    
        "File locks shall be released on first close by the locking process
        of any file descriptor for the file."
    
    Coverity may complain again about the leaked file descriptor; let's
    worry about that later.
    
    v1->v2:
    - add reference to 1bbd1592
    - explain the intentional fd leak in the source
    
    [1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/lockf.html
    
    Signed-off-by: Laszlo Ersek <lersek at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/os-posix.c b/os-posix.c
index 5c437ca..e3ed497 100644
--- a/os-posix.c
+++ b/os-posix.c
@@ -348,6 +348,6 @@ int qemu_create_pidfile(const char *filename)
         return -1;
     }
 
-    close(fd);
+    /* keep pidfile open & locked forever */
     return 0;
 }
commit d34e8f6e9d3a396c3327aa9807c83f9e1f4a7bd7
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date:   Sat Jan 21 11:13:53 2012 -0600

    main-loop: For tools, initialize timers as part of qemu_init_main_loop()
    
    In some cases initializing the alarm timers can lead to non-negligable
    overhead from programs that link against qemu-tool.o. At least,
    setting a max-resolution WinMM alarm timer via mm_start_timer() (the
    current default for Windows) can increase the "tick rate" on Windows
    OSs and affect frequency scaling, and in the case of tools that run
    in guest OSs such has qemu-ga, the impact can be fairly dramatic
    (+20%/20% user/sys time on a core 2 processor was observed from an idle
    Windows XP guest).
    
    This patch doesn't address the issue directly (not sure what a good
    solution would be for Windows, or what other situations it might be
    noticeable), but it at least limits the scope of the issue to programs
    that "opt-in" to using the main-loop.c functions by only enabling alarm
    timers when qemu_init_main_loop() is called, which is already required
    to make use of those facilities, so existing users shouldn't be
    affected.
    
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/main-loop.c b/main-loop.c
index 62d95b9..db23de0 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -199,7 +199,7 @@ static int qemu_signal_init(void)
 }
 #endif
 
-int qemu_init_main_loop(void)
+int main_loop_init(void)
 {
     int ret;
 
diff --git a/main-loop.h b/main-loop.h
index f971013..4987041 100644
--- a/main-loop.h
+++ b/main-loop.h
@@ -41,10 +41,22 @@
  * SIGUSR2, thread signals (SIGFPE, SIGILL, SIGSEGV, SIGBUS) and real-time
  * signals if available.  Remember that Windows in practice does not have
  * signals, though.
+ *
+ * In the case of QEMU tools, this will also start/initialize timers.
  */
 int qemu_init_main_loop(void);
 
 /**
+ * main_loop_init: Initializes main loop
+ *
+ * Internal (but shared for compatibility reasons) initialization routine
+ * for the main loop. This should not be used by applications directly,
+ * use qemu_init_main_loop() instead.
+ *
+ */
+int main_loop_init(void);
+
+/**
  * main_loop_wait: Run one iteration of the main loop.
  *
  * If @nonblocking is true, poll for events, otherwise suspend until
diff --git a/qemu-tool.c b/qemu-tool.c
index 6b69668..183a583 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -83,11 +83,12 @@ void qemu_clock_warp(QEMUClock *clock)
 {
 }
 
-static void __attribute__((constructor)) init_main_loop(void)
+int qemu_init_main_loop(void)
 {
     init_clocks();
     init_timer_alarm();
     qemu_clock_enable(vm_clock, false);
+    return main_loop_init();
 }
 
 void slirp_select_fill(int *pnfds, fd_set *readfds,
diff --git a/vl.c b/vl.c
index 138f6bc..2d464cf 100644
--- a/vl.c
+++ b/vl.c
@@ -2167,6 +2167,11 @@ static void free_and_trace(gpointer mem)
     free(mem);
 }
 
+int qemu_init_main_loop(void)
+{
+    return main_loop_init();
+}
+
 int main(int argc, char **argv, char **envp)
 {
     const char *gdbstub_dev = NULL;
commit ee77dfb26a5c7972bd7100e910c7427bcb1c8cae
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date:   Fri Jan 20 19:08:27 2012 -0600

    main-loop: Fix SetEvent() on uninitialized handle on win32
    
    The __attribute__((constructor)) init_main_loop() automatically get
    called if qemu-tool.o is linked in. On win32, this leads to
    a qemu_notify_event() call which attempts to SetEvent() on a HANDLE that
    won't be initialized until qemu_init_main_loop() is manually called,
    breaking qemu-tools.o programs on Windows at runtime.
    
    This patch checks for an initialized event handle before attempting to
    set it, which is analoguous to how we deal with an unitialized
    io_thread_fd in the posix implementation.
    
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
    Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/main-loop.c b/main-loop.c
index 692381c..62d95b9 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -164,7 +164,7 @@ static int qemu_signal_init(void)
 
 #else /* _WIN32 */
 
-HANDLE qemu_event_handle;
+HANDLE qemu_event_handle = NULL;
 
 static void dummy_event_handler(void *opaque)
 {
@@ -183,6 +183,9 @@ static int qemu_event_init(void)
 
 void qemu_notify_event(void)
 {
+    if (!qemu_event_handle) {
+        return;
+    }
     if (!SetEvent(qemu_event_handle)) {
         fprintf(stderr, "qemu_notify_event: SetEvent failed: %ld\n",
                 GetLastError());
commit 6fbcef296a7e34b236d836cf7b42c38e78de6fb6
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Mon Jan 30 11:27:33 2012 +0100

    optionroms: Silence intermediate file removal
    
    The build process of optionroms spits out an "rm ..." line. Moreover, it
    removes all .o files that can be handy for debugging purposes. So
    disable automatic intermediate removal.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile
index 51da288..2caf7e6 100644
--- a/pc-bios/optionrom/Makefile
+++ b/pc-bios/optionrom/Makefile
@@ -16,6 +16,9 @@ QEMU_CFLAGS = $(CFLAGS)
 
 build-all: multiboot.bin linuxboot.bin
 
+# suppress auto-removal of intermediate files
+.SECONDARY:
+
 %.img: %.o
 	$(call quiet-command,$(LD) -Ttext 0 -e _start -s -o $@ $<,"  Building $(TARGET_DIR)$@")
 
commit 02df4d6fb4dad5b82165fb603cc403256574cbf8
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Jan 31 13:45:31 2012 +0100

    sdl: Limit sdl_grab_end in handle_activation to Windows hosts
    
    There are scenarios on Linux with some SDL versions where
    handle_activation is continuous invoked with state = SDL_APPINPUTFOCUS
    and gain = 0 while we grabbed the input. This causes a ping-pong when we
    grab the input after an absolute mouse entered the window.
    
    As this sdl_grab_end was once introduced to work around a Windows-only
    issue (0294ffb9c8), limit it to that platform.
    
    CC: Erik Rull <erik.rull at rdsoftware.de>
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index 73e5839..6f8091c 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -828,10 +828,14 @@ static void handle_mousebutton(DisplayState *ds, SDL_Event *ev)
 
 static void handle_activation(DisplayState *ds, SDL_Event *ev)
 {
+#ifdef _WIN32
+    /* Disable grab if the window no longer has the focus
+     * (Windows-only workaround) */
     if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
         !ev->active.gain && !gui_fullscreen) {
         sdl_grab_end();
     }
+#endif
     if (!gui_grab && ev->active.gain && is_graphic_console() &&
         (kbd_mouse_is_absolute() || absolute_enabled)) {
         absolute_mouse_grab();
commit 822f98d2a56c8dcc857bb6a4c4da6382787533a0
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Jan 31 13:45:30 2012 +0100

    sdl: Grab input on end of non-absolute mouse click
    
    By grabbing the input already on button down, we leave the button in
    that state for the host GUI. Thus it takes another click after releasing
    the input again to synchronize the mouse button state.
    
    Avoid this by grabbing on button up.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index 0d3a889..73e5839 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -802,8 +802,7 @@ static void handle_mousebutton(DisplayState *ds, SDL_Event *ev)
 
     bev = &ev->button;
     if (!gui_grab && !kbd_mouse_is_absolute()) {
-        if (ev->type == SDL_MOUSEBUTTONDOWN &&
-            (bev->button == SDL_BUTTON_LEFT)) {
+        if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) {
             /* start grabbing all events */
             sdl_grab_start();
         }
commit eaa2e027b73c9afca623d877c91150a94c83049d
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Jan 31 13:45:29 2012 +0100

    Revert "Handle SDL grabs failing (Mark McLoughlin)"
    
    This reverts commit 6bb816031f8bc0aafc3476e6dfa4293ee3a5f106.
    
    SDL_WM_GrabInput does not reliably bail out if grabbing is impossible.
    So if we get here, we already lost and will block. But this can no
    longer happen due to the check in sdl_grab_start. So this patch became
    obsolete.
    
    Conflicts:
    
    	sdl.c
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index d845efb..0d3a889 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -475,12 +475,9 @@ static void sdl_grab_start(void)
             SDL_WarpMouse(guest_x, guest_y);
     } else
         sdl_hide_cursor();
-
-    if (SDL_WM_GrabInput(SDL_GRAB_ON) == SDL_GRAB_ON) {
-        gui_grab = 1;
-        sdl_update_caption();
-    } else
-        sdl_show_cursor();
+    SDL_WM_GrabInput(SDL_GRAB_ON);
+    gui_grab = 1;
+    sdl_update_caption();
 }
 
 static void sdl_grab_end(void)
commit 85f94f868fcd868f0f605e9d3c1ad6351c557190
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Jan 31 13:45:28 2012 +0100

    sdl: Fix block prevention of SDL_WM_GrabInput
    
    Consistently check for SDL_APPINPUTFOCUS before trying to grab the input
    focus. Just checking for SDL_APPACTIVE doesn't work. Moving the check to
    sdl_grab_start allows for some consolidation.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index 384276d..d845efb 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -461,6 +461,14 @@ static void sdl_show_cursor(void)
 
 static void sdl_grab_start(void)
 {
+    /*
+     * If the application is not active, do not try to enter grab state. This
+     * prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from blocking all the
+     * application (SDL bug).
+     */
+    if (!(SDL_GetAppState() & SDL_APPINPUTFOCUS)) {
+        return;
+    }
     if (guest_cursor) {
         SDL_SetCursor(guest_sprite);
         if (!kbd_mouse_is_absolute() && !absolute_enabled)
@@ -487,12 +495,10 @@ static void absolute_mouse_grab(void)
 {
     int mouse_x, mouse_y;
 
-    if (SDL_GetAppState() & SDL_APPINPUTFOCUS) {
-        SDL_GetMouseState(&mouse_x, &mouse_y);
-        if (mouse_x > 0 && mouse_x < real_screen->w - 1 &&
-            mouse_y > 0 && mouse_y < real_screen->h - 1) {
-            sdl_grab_start();
-        }
+    SDL_GetMouseState(&mouse_x, &mouse_y);
+    if (mouse_x > 0 && mouse_x < real_screen->w - 1 &&
+        mouse_y > 0 && mouse_y < real_screen->h - 1) {
+        sdl_grab_start();
     }
 }
 
@@ -745,11 +751,7 @@ static void handle_keyup(DisplayState *ds, SDL_Event *ev)
         if (gui_keysym == 0) {
             /* exit/enter grab if pressing Ctrl-Alt */
             if (!gui_grab) {
-                /* If the application is not active, do not try to enter grab
-                 * state. It prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from
-                 * blocking all the application (SDL bug). */
-                if (is_graphic_console() &&
-                    SDL_GetAppState() & SDL_APPACTIVE) {
+                if (is_graphic_console()) {
                     sdl_grab_start();
                 }
             } else if (!gui_fullscreen) {
@@ -779,7 +781,7 @@ static void handle_mousemotion(DisplayState *ds, SDL_Event *ev)
             ev->motion.x == max_x || ev->motion.y == max_y)) {
             sdl_grab_end();
         }
-        if (!gui_grab && SDL_GetAppState() & SDL_APPINPUTFOCUS &&
+        if (!gui_grab &&
             (ev->motion.x > 0 && ev->motion.x < max_x &&
             ev->motion.y > 0 && ev->motion.y < max_y)) {
             sdl_grab_start();
commit 6659635619721f319be80e114a65c3386d9bf8a0
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Jan 31 13:45:27 2012 +0100

    sdl: Do not grab mouse on mode switch while in background
    
    When the mouse mode changes to absolute while the SDL windows is not in
    focus, refrain from grabbing the input. It would steal from some other
    window.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index 8cafc44..384276d 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -483,12 +483,27 @@ static void sdl_grab_end(void)
     sdl_update_caption();
 }
 
+static void absolute_mouse_grab(void)
+{
+    int mouse_x, mouse_y;
+
+    if (SDL_GetAppState() & SDL_APPINPUTFOCUS) {
+        SDL_GetMouseState(&mouse_x, &mouse_y);
+        if (mouse_x > 0 && mouse_x < real_screen->w - 1 &&
+            mouse_y > 0 && mouse_y < real_screen->h - 1) {
+            sdl_grab_start();
+        }
+    }
+}
+
 static void sdl_mouse_mode_change(Notifier *notify, void *data)
 {
     if (kbd_mouse_is_absolute()) {
         if (!absolute_enabled) {
-            sdl_grab_start();
             absolute_enabled = 1;
+            if (is_graphic_console()) {
+                absolute_mouse_grab();
+            }
         }
     } else if (absolute_enabled) {
         if (!gui_fullscreen) {
@@ -571,19 +586,6 @@ static void toggle_full_screen(DisplayState *ds)
     vga_hw_update();
 }
 
-static void absolute_mouse_grab(void)
-{
-    int mouse_x, mouse_y;
-
-    if (SDL_GetAppState() & SDL_APPINPUTFOCUS) {
-        SDL_GetMouseState(&mouse_x, &mouse_y);
-        if (mouse_x > 0 && mouse_x < real_screen->w - 1 &&
-            mouse_y > 0 && mouse_y < real_screen->h - 1) {
-            sdl_grab_start();
-        }
-    }
-}
-
 static void handle_keydown(DisplayState *ds, SDL_Event *ev)
 {
     int mod_state;
commit 25de59350606772a4df479f0f49721281091ec56
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Fri Jan 27 19:55:43 2012 +0100

    Improve default machine options usability
    
    So far we overwrite the machine options completely with defaults if no
    accel=value is provided. More user friendly is to fill in only
    unspecified options. The new qemu_opts_set_defaults enables this.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/vl.c b/vl.c
index 6af0f83..138f6bc 100644
--- a/vl.c
+++ b/vl.c
@@ -3153,21 +3153,8 @@ int main(int argc, char **argv, char **envp)
      * specified either by the configuration file or by the command line.
      */
     if (machine->default_machine_opts) {
-        QemuOptsList *list = qemu_find_opts("machine");
-        const char *p = NULL;
-
-        if (!QTAILQ_EMPTY(&list->head)) {
-            p = qemu_opt_get(QTAILQ_FIRST(&list->head), "accel");
-        }
-        if (p == NULL) {
-            qemu_opts_reset(list);
-            opts = qemu_opts_parse(list, machine->default_machine_opts, 0);
-            if (!opts) {
-                fprintf(stderr, "parse error for machine %s: %s\n",
-                        machine->name, machine->default_machine_opts);
-                exit(1);
-            }
-        }
+        qemu_opts_set_defaults(qemu_find_opts("machine"),
+                               machine->default_machine_opts, 0);
     }
 
     qemu_opts_foreach(qemu_find_opts("device"), default_driver_check, NULL, 0);
commit 433acf0daceb12afd9680bcbc668002f9b274ad2
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Mon Jan 23 20:15:12 2012 +0100

    mc146818rtc: Use lost_tick_policy property
    
    Allow to configure the MC146818 RTC via the new lost tick policy
    property and replace rtc_td_hack with this mechanism.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 685eb89..e6e4cb7 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
 }
 
@@ -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);
 
@@ -713,6 +723,8 @@ static DeviceInfo mc146818rtc_info = {
     .class_init          = rtc_class_initfn,
     .props    = (Property[]) {
         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(),
     }
 };
diff --git a/sysemu.h b/sysemu.h
index caff268..9d5ce33 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -105,7 +105,6 @@ extern int graphic_depth;
 extern DisplayType display_type;
 extern const char *keyboard_layout;
 extern int win2k_install_hack;
-extern int rtc_td_hack;
 extern int alt_grab;
 extern int ctrl_grab;
 extern int usb_enabled;
diff --git a/vl.c b/vl.c
index d88a18c..6af0f83 100644
--- a/vl.c
+++ b/vl.c
@@ -201,7 +201,6 @@ CharDriverState *serial_hds[MAX_SERIAL_PORTS];
 CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
 CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
 int win2k_install_hack = 0;
-int rtc_td_hack = 0;
 int usb_enabled = 0;
 int singlestep = 0;
 int smp_cpus = 1;
@@ -540,9 +539,18 @@ static void configure_rtc(QemuOpts *opts)
     value = qemu_opt_get(opts, "driftfix");
     if (value) {
         if (!strcmp(value, "slew")) {
-            rtc_td_hack = 1;
+            static GlobalProperty slew_lost_ticks[] = {
+                {
+                    .driver   = "mc146818rtc",
+                    .property = "lost_tick_policy",
+                    .value    = "slew",
+                },
+                { /* end of list */ }
+            };
+
+            qdev_prop_register_global_list(slew_lost_ticks);
         } else if (!strcmp(value, "none")) {
-            rtc_td_hack = 0;
+            /* discard is default */
         } else {
             fprintf(stderr, "qemu: invalid option value '%s'\n", value);
             exit(1);
@@ -2836,9 +2844,19 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_win2k_hack:
                 win2k_install_hack = 1;
                 break;
-            case QEMU_OPTION_rtc_td_hack:
-                rtc_td_hack = 1;
+            case QEMU_OPTION_rtc_td_hack: {
+                static GlobalProperty slew_lost_ticks[] = {
+                    {
+                        .driver   = "mc146818rtc",
+                        .property = "lost_tick_policy",
+                        .value    = "slew",
+                    },
+                    { /* end of list */ }
+                };
+
+                qdev_prop_register_global_list(slew_lost_ticks);
                 break;
+            }
             case QEMU_OPTION_acpitable:
                 do_acpitable_option(optarg);
                 break;
commit 4f6dd9af9cf0a0138ff7733f45568c4e20b3bad1
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Fri Jan 27 19:54:54 2012 +0100

    qemu-option: Introduce default mechanism
    
    This adds qemu_opts_set_defaults, an interface provide default values
    for a QemuOpts set. Default options are parsed from a string and then
    prepended to the list of existing options, or they serve as the sole
    QemuOpts set.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/qemu-option.c b/qemu-option.c
index a303f87..4626ccf 100644
--- a/qemu-option.c
+++ b/qemu-option.c
@@ -603,7 +603,8 @@ static void qemu_opt_del(QemuOpt *opt)
     g_free(opt);
 }
 
-int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
+static int opt_set(QemuOpts *opts, const char *name, const char *value,
+                   bool prepend)
 {
     QemuOpt *opt;
     const QemuOptDesc *desc = opts->list->desc;
@@ -626,7 +627,11 @@ int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
     opt = g_malloc0(sizeof(*opt));
     opt->name = g_strdup(name);
     opt->opts = opts;
-    QTAILQ_INSERT_TAIL(&opts->head, opt, next);
+    if (prepend) {
+        QTAILQ_INSERT_HEAD(&opts->head, opt, next);
+    } else {
+        QTAILQ_INSERT_TAIL(&opts->head, opt, next);
+    }
     if (desc[i].name != NULL) {
         opt->desc = desc+i;
     }
@@ -640,6 +645,11 @@ int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
     return 0;
 }
 
+int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
+{
+    return opt_set(opts, name, value, false);
+}
+
 int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val)
 {
     QemuOpt *opt;
@@ -691,6 +701,9 @@ QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id)
 
     QTAILQ_FOREACH(opts, &list->head, next) {
         if (!opts->id) {
+            if (!id) {
+                return opts;
+            }
             continue;
         }
         if (strcmp(opts->id, id) != 0) {
@@ -806,7 +819,8 @@ int qemu_opts_print(QemuOpts *opts, void *dummy)
     return 0;
 }
 
-int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname)
+static int opts_do_parse(QemuOpts *opts, const char *params,
+                         const char *firstname, bool prepend)
 {
     char option[128], value[1024];
     const char *p,*pe,*pc;
@@ -841,7 +855,7 @@ int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname
         }
         if (strcmp(option, "id") != 0) {
             /* store and parse */
-            if (qemu_opt_set(opts, option, value) == -1) {
+            if (opt_set(opts, option, value, prepend) == -1) {
                 return -1;
             }
         }
@@ -852,8 +866,13 @@ int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname
     return 0;
 }
 
-QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
-                          int permit_abbrev)
+int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname)
+{
+    return opts_do_parse(opts, params, firstname, false);
+}
+
+static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
+                            int permit_abbrev, bool defaults)
 {
     const char *firstname;
     char value[1024], *id = NULL;
@@ -870,11 +889,19 @@ QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
         get_opt_value(value, sizeof(value), p+4);
         id = value;
     }
-    opts = qemu_opts_create(list, id, 1);
+    if (defaults) {
+        if (!id && !QTAILQ_EMPTY(&list->head)) {
+            opts = qemu_opts_find(list, NULL);
+        } else {
+            opts = qemu_opts_create(list, id, 0);
+        }
+    } else {
+        opts = qemu_opts_create(list, id, 1);
+    }
     if (opts == NULL)
         return NULL;
 
-    if (qemu_opts_do_parse(opts, params, firstname) != 0) {
+    if (opts_do_parse(opts, params, firstname, defaults) != 0) {
         qemu_opts_del(opts);
         return NULL;
     }
@@ -882,6 +909,21 @@ QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
     return opts;
 }
 
+QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
+                          int permit_abbrev)
+{
+    return opts_parse(list, params, permit_abbrev, false);
+}
+
+void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
+                            int permit_abbrev)
+{
+    QemuOpts *opts;
+
+    opts = opts_parse(list, params, permit_abbrev, true);
+    assert(opts);
+}
+
 static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque)
 {
     char buf[32];
diff --git a/qemu-option.h b/qemu-option.h
index 07958e4..e6f61e6 100644
--- a/qemu-option.h
+++ b/qemu-option.h
@@ -125,6 +125,8 @@ void qemu_opts_del(QemuOpts *opts);
 int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc);
 int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname);
 QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, int permit_abbrev);
+void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
+                            int permit_abbrev);
 QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict);
 QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict);
 
commit 4e4fa398db69e22dcad23114eb7e33b4d89b10c4
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Mon Jan 23 20:15:11 2012 +0100

    qdev: Introduce lost tick policy property
    
    Potentially tick-generating timer devices will gain a common property:
    lock_tick_policy. It allows to encode 4 different ways how to deal with
    tick events the guest did not process in time:
    
    discard - ignore lost ticks (e.g. if the guest compensates for them
              already)
    delay   - replay all lost ticks in a row once the guest accepts them
              again
    merge   - if multiple ticks are lost, all of them are merged into one
              which is replayed once the guest accepts it again
    slew    - lost ticks are gradually replayed at a higher frequency than
              the original tick
    
    Not all timer device will need to support all modes. However, all need
    to accept the configuration via this common property.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index c98219a..028bee7 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -885,6 +885,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 --- */
 
 /*
@@ -1127,6 +1176,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);
diff --git a/hw/qdev.h b/hw/qdev.h
index c9572a5..364e91d 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -158,6 +158,7 @@ enum PropertyType {
     PROP_TYPE_UINT64,
     PROP_TYPE_TADDR,
     PROP_TYPE_MACADDR,
+    PROP_TYPE_LOSTTICKPOLICY,
     PROP_TYPE_DRIVE,
     PROP_TYPE_CHR,
     PROP_TYPE_STRING,
@@ -307,6 +308,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;
@@ -367,6 +369,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()               \
     {}
@@ -389,6 +394,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);
diff --git a/qemu-common.h b/qemu-common.h
index 6ab7dfb..8b69a9e 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -250,6 +250,13 @@ typedef struct QEMUSGList QEMUSGList;
 
 typedef uint64_t pcibus_t;
 
+typedef enum LostTickPolicy {
+    LOST_TICK_DISCARD,
+    LOST_TICK_DELAY,
+    LOST_TICK_MERGE,
+    LOST_TICK_SLEW,
+} LostTickPolicy;
+
 void tcg_exec_init(unsigned long tb_size);
 bool tcg_enabled(void);
 
commit 67ed96f9f25ddd69e23c455d44d389054addf165
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Feb 1 18:50:42 2012 +0000

    Makefile: Remove linux-headers/asm symlink on distclean
    
    configure creates a linux-headers/asm symlink. Remove this when
    doing a distclean.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/Makefile b/Makefile
index d172cbf..2560b59 100644
--- a/Makefile
+++ b/Makefile
@@ -233,6 +233,7 @@ distclean: clean
 	rm -f qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp
 	rm -f qemu-doc.vr
 	rm -f config.log
+	rm -f linux-headers/asm
 	rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr
 	for d in $(TARGET_DIRS) $(QEMULIBS); do \
 	rm -rf $$d || exit 1 ; \
commit 771124e1a61f73886ab16b4c9ce01eeffb74ce2b
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Jan 17 13:23:13 2012 +0000

    exec.c: Clarify comment about tlb_flush() flush_global parameter
    
    Clarify the comment about tlb_flush()'s flush_global parameter,
    so it is clearer what it does and why it is OK that the implementation
    currently ignores it.
    
    Reviewed-by: Andreas F=C3=A4rber <afaerber at suse.de>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/exec.c b/exec.c
index 5b9eb9a..b81677a 100644
--- a/exec.c
+++ b/exec.c
@@ -1876,8 +1876,18 @@ static CPUTLBEntry s_cputlb_empty_entry = {
     .addend     = -1,
 };
 
-/* NOTE: if flush_global is true, also flush global entries (not
-   implemented yet) */
+/* NOTE:
+ * If flush_global is true (the usual case), flush all tlb entries.
+ * If flush_global is false, flush (at least) all tlb entries not
+ * marked global.
+ *
+ * Since QEMU doesn't currently implement a global/not-global flag
+ * for tlb entries, at the moment tlb_flush() will also flush all
+ * tlb entries in the flush_global == false case. This is OK because
+ * CPU architectures generally permit an implementation to drop
+ * entries from the TLB at any time, so flushing more entries than
+ * required is only an efficiency issue, not a correctness issue.
+ */
 void tlb_flush(CPUState *env, int flush_global)
 {
     int i;
commit 23704102ba9e24ad5eb913f240fdcf1bd45d38b1
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Thu Jan 19 22:57:11 2012 +0530

    hw/9pfs: Update MAINTAINERS file
    
    Acked-by: Venkateswararao Jujjuri <jvrao at linux.vnet.ibm.com>
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/MAINTAINERS b/MAINTAINERS
index 882958e..173e893 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -428,9 +428,11 @@ S: Supported
 F: hw/virtio*
 
 virtio-9p
-M: Venkateswararao Jujjuri (JV) <jvrao at linux.vnet.ibm.com>
+M: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
 S: Supported
-F: hw/virtio-9p*
+F: hw/9pfs/ fsdev/
+T: https://github.com/kvaneesh/QEMU
+
 
 virtio-blk
 M: Kevin Wolf <kwolf at redhat.com>
commit 1bdd687454e89a2fd6902b95d912b1d7113f3965
Author: Stefan Weil <sw at weilnetz.de>
Date:   Fri Jan 27 18:53:49 2012 +0100

    MAINTAINERS: Add a section for the host OS and a W32 maintainer
    
    Up to now, there was no special section for the different
    host operating systems used with QEMU.
    
    scripts/get_maintainer.pl did not show a maintainer for
    OS specific files and patches.
    
    Therefore I added three hosts systems:
    
    * POSIX for the majority of host systems which are supported.
      This includes BSD and Linux host systems.
    
    * LINUX is a special case of POSIX needed for some Linux specific
      files and directories.
    
    * W32, W64 for a well known family of closed source operating systems.
    
    I also added myself as a maintainer for W32, W64.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/MAINTAINERS b/MAINTAINERS
index 73c0a10..882958e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -161,6 +161,26 @@ S: Supported
 F: xen-*
 F: */xen*
 
+Hosts:
+------
+
+LINUX
+L: qemu-devel at nongnu.org
+S: Maintained
+F: linux-*
+F: linux-headers/
+
+POSIX
+L: qemu-devel at nongnu.org
+S: Maintained
+F: *posix*
+
+W32, W64
+L: qemu-devel at nongnu.org
+M: Stefan Weil <sw at weilnetz.de>
+S: Maintained
+F: *win32*
+
 ARM Machines
 ------------
 Gumstix
commit 5f01e06f1fc7904a03e02b68c829aa25c2085baa
Author: Sergei Trofimovich <slyfox at gentoo.org>
Date:   Tue Jan 31 22:03:58 2012 +0300

    ./configure: add link check for nss-smartcard
    
    Current './configure --static && make' fails for me:
    
        LINK  qemu-nbd
        /usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lssl3
        /usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lsmime3
        /usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lnssutil3
        /usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lnss3
        /usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lplds4
        /usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lplc4
        /usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lnspr4
    
    My system does not provide static libraries for nss, so
    fix autoconfiguration by link checking.
    
    Signed-off-by: Sergei Trofimovich <slyfox at gentoo.org>
    CC: qemu-trivial <qemu-trivial at nongnu.org>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index 8fd5404..3b0b300 100755
--- a/configure
+++ b/configure
@@ -2528,11 +2528,16 @@ if test "$smartcard" != "no" ; then
     smartcard_cflags=""
     # TODO - what's the minimal nss version we support?
     if test "$smartcard_nss" != "no"; then
-        if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 ; then
+      cat > $TMPC << EOF
+#include <pk11pub.h>
+int main(void) { PK11_FreeSlot(0); return 0; }
+EOF
+        smartcard_cflags="-I\$(SRC_PATH)/libcacard"
+        libcacard_libs=$($pkg_config --libs nss 2>/dev/null)
+        libcacard_cflags=$($pkg_config --cflags nss 2>/dev/null)
+        if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 && \
+          compile_prog "$smartcard_cflags $libcacard_cflags" "$libcacard_libs"; then
             smartcard_nss="yes"
-            smartcard_cflags="-I\$(SRC_PATH)/libcacard"
-            libcacard_libs=$($pkg_config --libs nss 2>/dev/null)
-            libcacard_cflags=$($pkg_config --cflags nss 2>/dev/null)
             QEMU_CFLAGS="$QEMU_CFLAGS $smartcard_cflags $libcacard_cflags"
             LIBS="$libcacard_libs $LIBS"
         else
commit 17884d7b6462b0fe497f08fec6091ffbe04caa8d
Author: Sergei Trofimovich <slyfox at gentoo.org>
Date:   Tue Jan 31 22:03:45 2012 +0300

    ./configure: request pkg-config to provide private libs when static linking
    
    Added wrapper around pkg-config to allow:
    - safe options injection via ${QEMU_PKG_CONFIG_FLAGS}
    - spaces in path to pkg-config
    
    Signed-off-by: Sergei Trofimovich <slyfox at gentoo.org>
    CC: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index f69e08f..8fd5404 100755
--- a/configure
+++ b/configure
@@ -234,7 +234,11 @@ ld="${LD-${cross_prefix}ld}"
 libtool="${LIBTOOL-${cross_prefix}libtool}"
 strip="${STRIP-${cross_prefix}strip}"
 windres="${WINDRES-${cross_prefix}windres}"
-pkg_config="${PKG_CONFIG-${cross_prefix}pkg-config}"
+pkg_config_exe="${PKG_CONFIG-${cross_prefix}pkg-config}"
+query_pkg_config() {
+    "${pkg_config_exe}" ${QEMU_PKG_CONFIG_FLAGS} "$@"
+}
+pkg_config=query_pkg_config
 sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
 
 # default flags for all hosts
@@ -553,6 +557,7 @@ for opt do
   --static)
     static="yes"
     LDFLAGS="-static $LDFLAGS"
+    QEMU_PKG_CONFIG_FLAGS="--static $QEMU_PKG_CONFIG_FLAGS"
   ;;
   --mandir=*) mandir="$optarg"
   ;;
@@ -1449,8 +1454,8 @@ fi
 ##########################################
 # pkg-config probe
 
-if ! has $pkg_config; then
-  echo "Error: pkg-config binary '$pkg_config' not found"
+if ! has "$pkg_config_exe"; then
+  echo "Error: pkg-config binary '$pkg_config_exe' not found"
   exit 1
 fi
 
commit 1d84950234b2aea0f0e3e323ab35e20dbbc77bff
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Jan 20 13:05:00 2012 +0100

    m48t59: use rtc_clock for alarm timer
    
    This lets the RTC get adjustments from the host NTP client.
    The watchdog still uses the vm_clock.  The previous behavior is
    available with "-rtc clock=vm".
    
    Cc: Andreas Färber <afaerber at suse.de>
    Reviewed-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/m48t59.c b/hw/m48t59.c
index 262cfb8..bd610f0 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);
commit 0c685d2827ad591484b3ef667834a81967b5fad7
Author: Fabien Chouteau <chouteau at adacore.com>
Date:   Thu Jan 26 18:03:15 2012 +0100

    GRLIB UART: Add RX channel
    
    This patch implements the RX channel of GRLIB UART with a FIFO to
    improve data rate.
    
    Signed-off-by: Fabien Chouteau <chouteau at adacore.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
index dc12d58..f7755b0 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,
diff --git a/trace-events b/trace-events
index 75f6e17..5d05749 100644
--- a/trace-events
+++ b/trace-events
@@ -351,6 +351,7 @@ grlib_irqmp_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" valu
 # hw/grlib_apbuart.c
 grlib_apbuart_event(int event) "event:%d"
 grlib_apbuart_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"
+grlib_apbuart_readl_unknown(uint64_t addr) "addr 0x%"PRIx64""
 
 # hw/leon3.c
 leon3_set_irq(int intno) "Set CPU IRQ %d"
commit eed968607d656a218712df47a5e0432c21fd6994
Author: Daniel P. Berrange <berrange at redhat.com>
Date:   Mon Jan 16 18:11:40 2012 +0000

    hw/9pfs: Remove O_NOATIME flag from 9pfs open() calls in readonly mode
    
    When 2c74c2cb4bedddbfa67628fbd5f9273b4e0e9903 added support for
    the 'readonly' flag against 9p filesystems, it also made QEMU
    add the O_NOATIME flag as a side-effect.
    
    The O_NOATIME flag, however, may only be set by the file owner,
    or a user with CAP_FOWNER capability.  QEMU cannot assume that
    this is the case for filesytems exported to QEMU.
    
    eg, run QEMU as non-root, and attempt to pass the host OS
    filesystem through to the guest OS with readonly enable.
    The result is that the guest OS cannot open any files at
    all.
    
    If O_NOATIME is really required, it should be optionally
    enabled via a separate QEMU command line flag.
    
     * hw/9pfs/virtio-9p.c: Remove O_NOATIME
    
    Acked-by: M. Mohan Kumar <mohan at in.ibm.com>
    Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index dfe2025..a72ffc3 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -1391,7 +1391,6 @@ static void v9fs_open(void *opaque)
                 err = -EROFS;
                 goto out;
             }
-            flags |= O_NOATIME;
         }
         err = v9fs_co_open(pdu, fidp, flags);
         if (err < 0) {
commit 68e59e14605f9e6390d8d975f9ab919be9176bc2
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Sun Jan 15 23:31:04 2012 +0530

    hw/9pfs: Update MAINTAINERS file
    
    Acked-by: Venkateswararao Jujjuri <jvrao at linux.vnet.ibm.com>
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/MAINTAINERS b/MAINTAINERS
index de2a916..f9f131c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -399,9 +399,11 @@ S: Supported
 F: hw/virtio*
 
 virtio-9p
-M: Venkateswararao Jujjuri (JV) <jvrao at linux.vnet.ibm.com>
+M: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
 S: Supported
-F: hw/virtio-9p*
+F: hw/9pfs/ fsdev/
+T: https://github.com/kvaneesh/QEMU
+
 
 virtio-blk
 M: Kevin Wolf <kwolf at redhat.com>
commit 5fc6dbae7416d7be38565391d4c213fa9085c9fb
Author: M. Mohan Kumar <mohan at in.ibm.com>
Date:   Thu Jan 19 16:15:56 2012 +0530

    fsdev: Fix parameter parsing for proxy helper
    
    This fixes a crash when using sockfd with proxy FsDriver
    
    Signed-off-by: M. Mohan Kumar <mohan at in.ibm.com>
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index 4a507d8..f9a8270 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -1036,7 +1036,13 @@ int main(int argc, char **argv)
         return -1;
     }
 
-    if (*sock_name && (own_u == -1 || own_g == -1)) {
+    if (sock_name && sock != -1) {
+        fprintf(stderr, "both named socket and socket descriptor specified\n");
+        usage(argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    if (sock_name && (own_u == -1 || own_g == -1)) {
         fprintf(stderr, "owner uid:gid not specified, ");
         fprintf(stderr,
                 "owner uid:gid specifies who can access the socket file\n");
@@ -1064,7 +1070,7 @@ int main(int argc, char **argv)
     }
 
     do_log(LOG_INFO, "Started\n");
-    if (*sock_name) {
+    if (sock_name) {
         sock = proxy_socket(sock_name, own_u, own_g);
         if (sock < 0) {
             goto error;
commit 71f86cd6f396fe3ede575d7dde5dbabb4a6d006e
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Thu Jan 19 12:21:12 2012 +0530

    hw/9pfs: Fix crash when mounting with synthfs
    
    Some Fsdriver backend don't have fs_root. So check for that in
    migrate message.
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index e6ba6ba..dfe2025 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -986,7 +986,7 @@ static void v9fs_attach(void *opaque)
     s->root_fid = fid;
     /* disable migration */
     error_set(&s->migration_blocker, QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
-              s->ctx.fs_root, s->tag);
+              s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag);
     migrate_add_blocker(s->migration_blocker);
 out:
     put_fid(pdu, fidp);
commit 2d40564aaab3a99fe6ce00fc0fc893c02e9443ec
Author: M. Mohan Kumar <mohan at in.ibm.com>
Date:   Thu Jan 19 12:21:12 2012 +0530

    hw/9pfs: Preserve S_ISGID
    
    In passthrough security model in local fs driver, after a file creation
    chown and chmod are done to set the file credentials and mode as requested
    by 9p client. But if there was a request to create a file with S_ISGID
    bit, doing chown on that file resets the S_ISGID bit. So first call
    chown and then invoking chmod with proper mode bit retains the S_ISGID
    (if present/requested)
    
    This resulted in LTP mknod02, mknod03, mknod05, open10 test case
    failures. This patch fixes this issue.
    
    man 2 chown
    When the owner or group of an executable file are changed by an unprivileged
    user the S_ISUID  and  S_ISGID mode  bits are cleared.  POSIX does not specify
    whether this also should happen when root does the chown(); the Linux behavior
    depends on the kernel version.
    
    Signed-off-by: M. Mohan Kumar <mohan at in.ibm.com>
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c
index cb012c0..f96d17a 100644
--- a/hw/9pfs/virtio-9p-handle.c
+++ b/hw/9pfs/virtio-9p-handle.c
@@ -63,11 +63,11 @@ static int handle_update_file_cred(int dirfd, const char *name, FsCred *credp)
     if (fd < 0) {
         return fd;
     }
-    ret = fchmod(fd, credp->fc_mode & 07777);
+    ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
     if (ret < 0) {
         goto err_out;
     }
-    ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
+    ret = fchmod(fd, credp->fc_mode & 07777);
 err_out:
     close(fd);
     return ret;
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index 6e3f9d1..33a41d2 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -257,9 +257,6 @@ static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
 {
     char buffer[PATH_MAX];
 
-    if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
-        return -1;
-    }
     if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
                 credp->fc_gid) < 0) {
         /*
@@ -270,6 +267,10 @@ static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
             return -1;
         }
     }
+
+    if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
+        return -1;
+    }
     return 0;
 }
 
commit fd39941ac78fbe969e292eeb91415ec548bd97a6
Author: Avi Kivity <avi at redhat.com>
Date:   Sun Jan 29 16:47:47 2012 +0200

    Fix off-by-one in dirty bitmap functions
    
    Reported-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/exec-obsolete.h b/exec-obsolete.h
index 03cf35e..d2749d3 100644
--- a/exec-obsolete.h
+++ b/exec-obsolete.h
@@ -83,9 +83,10 @@ static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start,
     uint8_t *p;
     ram_addr_t addr, end;
 
-    end = start + length;
+    end = TARGET_PAGE_ALIGN(start + length);
+    start &= TARGET_PAGE_MASK;
     p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
-    for (addr = start; addr <= end; addr += TARGET_PAGE_SIZE) {
+    for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
         *p++ |= dirty_flags;
     }
 }
@@ -98,10 +99,11 @@ static inline void cpu_physical_memory_mask_dirty_range(ram_addr_t start,
     uint8_t *p;
     ram_addr_t addr, end;
 
-    end = start + length;
+    end = TARGET_PAGE_ALIGN(start + length);
+    start &= TARGET_PAGE_MASK;
     mask = ~dirty_flags;
     p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
-    for (addr = start; addr <= end; addr += TARGET_PAGE_SIZE) {
+    for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
         *p++ &= mask;
     }
 }
commit 9ec032d2aca18737f1ee0e8e37d06383928ec9a4
Merge: 0f36036... 0b03bdf...
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Jan 28 13:11:20 2012 +0000

    Merge branch 'target-arm.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm
    
    * 'target-arm.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm:
      Add Cortex-A15 CPU definition
      Add dummy implementation of generic timer cp15 registers
      arm: store the config_base_register during cpu_reset
      target-arm/helper.c: Don't assume softfloat int32 is 32 bits only
      target-arm: Fix implementation of TLB invalidate operations

commit 0f36036c5c1ce322119f62e0be49c6328ee29573
Author: Andreas Färber <afaerber at suse.de>
Date:   Fri Jan 27 20:08:52 2012 +0100

    unin_pci: Fix typos in device names
    
    Commit 999e12bbe85c5dcf49bef13bce4f97399c7105f4 (sysbus: apic: ioapic:
    convert to QEMU Object Model) introduced two typos, one of which broke
    the mac99 machine.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Cc: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 2b394c0..9822353 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -415,7 +415,7 @@ static void pci_unin_main_class_init(ObjectClass *klass, void *data)
 }
 
 static DeviceInfo pci_unin_main_info = {
-    .name = "uni-north-pci-pchost",
+    .name = "uni-north-pci-pcihost",
     .size = sizeof(UNINState),
     .class_init = pci_unin_main_class_init,
 };
@@ -454,7 +454,7 @@ static void pci_unin_internal_class_init(ObjectClass *klass, void *data)
 }
 
 static DeviceInfo pci_unin_internal_info = {
-    .name = "uni-north-internal-pci-pichost",
+    .name = "uni-north-internal-pci-pcihost",
     .size = sizeof(UNINState),
     .class_init = pci_unin_internal_class_init,
 };
commit 73093354418602a2ff5e43cb91a21b17fbf047d8
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Jan 25 13:37:36 2012 -0600

    qdev: change ambiguous qdev names
    
    Reported-by: Blue Swirl <blauwirbel at gmail.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index 173dab3..1a45420 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,
@@ -448,7 +448,7 @@ static void pbm_pci_host_class_init(ObjectClass *klass, void *data)
 }
 
 static DeviceInfo pbm_pci_host_info = {
-    .name = "pbm",
+    .name = "pbm-pci",
     .size = sizeof(PCIDevice),
     .class_init = pbm_pci_host_class_init,
 };
diff --git a/hw/dec_pci.c b/hw/dec_pci.c
index f0ecaff..333bad9 100644
--- a/hw/dec_pci.c
+++ b/hw/dec_pci.c
@@ -131,7 +131,7 @@ static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data)
 }
 
 static DeviceInfo pci_dec_21154_device_info = {
-    .name = "dec-21154",
+    .name = "dec-21154-sysbus",
     .size = sizeof(DECState),
     .class_init = pci_dec_21154_device_class_init,
 };
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index b6ac0d4..2a82eae 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -222,7 +222,7 @@ static void spapr_main_pci_host_class_init(ObjectClass *klass, void *data)
 }
 
 static DeviceInfo spapr_main_pci_host_info = {
-    .name = "spapr-pci-host-bridge",
+    .name = "spapr-pci-host-bridge-pci",
     .size = sizeof(PCIDevice),
     .class_init = spapr_main_pci_host_class_init,
 };
diff --git a/qom/object.c b/qom/object.c
index ef37e08..a12895f 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -87,6 +87,11 @@ TypeImpl *type_register(const TypeInfo *info)
 
     g_assert(info->name != NULL);
 
+    if (type_table_lookup(info->name) != NULL) {
+        fprintf(stderr, "Registering `%s' which already exists\n", info->name);
+        abort();
+    }
+
     ti->name = g_strdup(info->name);
     ti->parent = g_strdup(info->parent);
 
commit 19b6914a00d3e7be447be418da661d4cd870ee03
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Dec 21 20:57:49 2011 -0600

    virtio-s390: convert to QEMU Object Model
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index 8e34a78..565941a 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -50,11 +50,19 @@ struct BusInfo s390_virtio_bus_info = {
     .size       = sizeof(VirtIOS390Bus),
 };
 
-typedef struct {
-    DeviceInfo qdev;
+typedef struct VirtIOS390DeviceClass
+{
+    DeviceClass parent_class;
     int (*init)(VirtIOS390Device *dev);
-} VirtIOS390DeviceInfo;
+} VirtIOS390DeviceClass;
 
+#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)
 
 static const VirtIOBindings virtio_s390_bindings;
 
@@ -343,12 +351,19 @@ 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[]) {
+static void s390_virtio_net_class_init(ObjectClass *klass, void *data)
+{
+    VirtIOS390DeviceClass *dc = VIRTIO_S390_DEVICE_CLASS(klass);
+
+    dc->init = s390_virtio_net_init;
+}
+
+static DeviceInfo s390_virtio_net = {
+    .name = "virtio-net-s390",
+    .alias = "virtio-net",
+    .size = sizeof(VirtIOS390Device),
+    .class_init = s390_virtio_net_class_init,
+    .props = (Property[]) {
         DEFINE_NIC_PROPERTIES(VirtIOS390Device, nic),
         DEFINE_PROP_UINT32("x-txtimer", VirtIOS390Device,
                            net.txtimer, TX_TIMER_INTERVAL),
@@ -359,24 +374,38 @@ static VirtIOS390DeviceInfo s390_virtio_net = {
     },
 };
 
-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[]) {
+static void s390_virtio_blk_class_init(ObjectClass *klass, void *data)
+{
+    VirtIOS390DeviceClass *dc = VIRTIO_S390_DEVICE_CLASS(klass);
+
+    dc->init = s390_virtio_blk_init;
+}
+
+static DeviceInfo s390_virtio_blk = {
+    .name = "virtio-blk-s390",
+    .alias = "virtio-blk",
+    .size = sizeof(VirtIOS390Device),
+    .class_init = s390_virtio_blk_class_init,
+    .props = (Property[]) {
         DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block),
         DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial),
         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[]) {
+static void s390_virtio_serial_class_init(ObjectClass *klass, void *data)
+{
+    VirtIOS390DeviceClass *dc = VIRTIO_S390_DEVICE_CLASS(klass);
+
+    dc->init = s390_virtio_serial_init;
+}
+
+static DeviceInfo s390_virtio_serial = {
+    .name = "virtio-serial-s390",
+    .alias = "virtio-serial",
+    .size = sizeof(VirtIOS390Device),
+    .class_init = s390_virtio_serial_class_init,
+    .props = (Property[]) {
         DEFINE_PROP_UINT32("max_ports", VirtIOS390Device,
                            serial.max_virtserial_ports, 31),
         DEFINE_PROP_END_OF_LIST(),
@@ -385,24 +414,32 @@ static VirtIOS390DeviceInfo s390_virtio_serial = {
 
 static int s390_virtio_busdev_init(DeviceState *dev, DeviceInfo *info)
 {
-    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 s390_virtio_bus_register_withprop(DeviceInfo *info)
 {
-    info->qdev.init = s390_virtio_busdev_init;
-    info->qdev.bus_info = &s390_virtio_bus_info;
-    info->qdev.unplug = qdev_simple_unplug_cb;
+    info->init = s390_virtio_busdev_init;
+    info->bus_info = &s390_virtio_bus_info;
+    info->unplug = qdev_simple_unplug_cb;
 
-    assert(info->qdev.size >= sizeof(VirtIOS390Device));
-    qdev_register(&info->qdev);
+    assert(info->size >= sizeof(VirtIOS390Device));
+    qdev_register_subclass(info, TYPE_VIRTIO_S390_DEVICE);
 }
 
+static TypeInfo virtio_s390_device_info = {
+    .name = TYPE_VIRTIO_S390_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(VirtIOS390Device),
+    .abstract = true,
+};
+
 static void s390_virtio_register(void)
 {
+    type_register_static(&virtio_s390_device_info);
     s390_virtio_bus_register_withprop(&s390_virtio_serial);
     s390_virtio_bus_register_withprop(&s390_virtio_blk);
     s390_virtio_bus_register_withprop(&s390_virtio_net);
commit 999e12bbe85c5dcf49bef13bce4f97399c7105f4
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Tue Jan 24 13:12:29 2012 -0600

    sysbus: apic: ioapic: convert to QEMU Object Model
    
    This converts three devices because apic and ioapic are subclasses of sysbus.
    Converting subclasses independently of their base class is prohibitively hard.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index 521b8cc..b42c475 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -208,13 +208,20 @@ 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[]) {
+static void a9mp_priv_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = a9mp_priv_init;
+}
+
+static DeviceInfo a9mp_priv_info = {
+    .name = "a9mpcore_priv",
+    .size  = sizeof(a9mp_priv_state),
+    .vmsd = &vmstate_a9mp_priv,
+    .reset = a9mp_priv_reset,
+    .class_init = a9mp_priv_class_init,
+    .props = (Property[]) {
         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
diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c
index 7d924a3..8a68c7c 100644
--- a/hw/alpha_typhoon.c
+++ b/hw/alpha_typhoon.c
@@ -808,11 +808,18 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = typhoon_pcihost_init;
+}
+
+static DeviceInfo typhoon_pcihost_info = {
+    .name = "typhoon-pcihost",
+    .size = sizeof(TyphoonState),
+    .no_user = 1,
+    .class_init = typhoon_pcihost_class_init,
 };
 
 static void typhoon_register(void)
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index 70cfc77..173dab3 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -453,11 +453,18 @@ static DeviceInfo pbm_pci_host_info = {
     .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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pci_pbm_init_device;
+}
+
+static DeviceInfo pbm_host_info = {
+    .name = "pbm",
+    .size = sizeof(APBState),
+    .reset = pci_pbm_reset,
+    .class_init = pbm_host_class_init,
 };
 
 static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data)
diff --git a/hw/apic.c b/hw/apic.c
index e59c964..353119d 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -763,13 +763,20 @@ static void apic_init(APICCommonState *s)
     local_apics[s->idx] = s;
 }
 
-static APICCommonInfo apic_info = {
-    .busdev.qdev.name = "apic",
-    .init = apic_init,
-    .set_base = apic_set_base,
-    .set_tpr = apic_set_tpr,
-    .external_nmi = apic_external_nmi,
-    .post_load = apic_post_load,
+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 DeviceInfo apic_info = {
+    .name = "apic",
+    .class_init = apic_class_init,
 };
 
 static void apic_register_devices(void)
diff --git a/hw/apic_common.c b/hw/apic_common.c
index ac06147..9a3b1c5 100644
--- a/hw/apic_common.c
+++ b/hw/apic_common.c
@@ -25,35 +25,40 @@ static int apic_irq_delivered;
 
 void cpu_set_apic_base(DeviceState *d, uint64_t val)
 {
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    APICCommonInfo *info;
-
     trace_cpu_set_apic_base(val);
 
-    if (s) {
-        info = DO_UPCAST(APICCommonInfo, busdev.qdev, qdev_get_info(&s->busdev.qdev));
+    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)
 {
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-
-    trace_cpu_get_apic_base(s ? (uint64_t)s->apicbase : 0);
-
-    return s ? s->apicbase : 0;
+    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 = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    APICCommonInfo *info;
+    APICCommonState *s;
+    APICCommonClass *info;
 
-    if (s) {
-        info = DO_UPCAST(APICCommonInfo, busdev.qdev, qdev_get_info(&s->busdev.qdev));
-        info->set_tpr(s, val);
+    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)
@@ -86,10 +91,9 @@ int apic_get_irq_delivered(void)
 
 void apic_deliver_nmi(DeviceState *d)
 {
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    APICCommonInfo *info;
+    APICCommonState *s = APIC_COMMON(d);
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
 
-    info = DO_UPCAST(APICCommonInfo, busdev.qdev, qdev_get_info(&s->busdev.qdev));
     info->external_nmi(s);
 }
 
@@ -223,8 +227,8 @@ static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
 
 static int apic_init_common(SysBusDevice *dev)
 {
-    APICCommonState *s = FROM_SYSBUS(APICCommonState, dev);
-    APICCommonInfo *info;
+    APICCommonState *s = APIC_COMMON(dev);
+    APICCommonClass *info;
     static int apic_no;
 
     if (apic_no >= MAX_APICS) {
@@ -232,7 +236,7 @@ static int apic_init_common(SysBusDevice *dev)
     }
     s->idx = apic_no++;
 
-    info = DO_UPCAST(APICCommonInfo, busdev.qdev, qdev_get_info(&s->busdev.qdev));
+    info = APIC_COMMON_GET_CLASS(s);
     info->init(s);
 
     sysbus_init_mmio(&s->busdev, &s->io_memory);
@@ -241,9 +245,8 @@ static int apic_init_common(SysBusDevice *dev)
 
 static int apic_dispatch_post_load(void *opaque, int version_id)
 {
-    APICCommonState *s = opaque;
-    APICCommonInfo *info =
-        DO_UPCAST(APICCommonInfo, busdev.qdev, qdev_get_info(&s->busdev.qdev));
+    APICCommonState *s = APIC_COMMON(opaque);
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
 
     if (info->post_load) {
         info->post_load(s);
@@ -289,14 +292,35 @@ static Property apic_properties_common[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
+static void apic_common_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sc->init = apic_init_common;
+}
 
-void apic_qdev_register(APICCommonInfo *info)
+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,
+};
+
+void apic_qdev_register(DeviceInfo *info)
 {
-    info->busdev.init = apic_init_common;
-    info->busdev.qdev.size = sizeof(APICCommonState),
-    info->busdev.qdev.vmsd = &vmstate_apic_common;
-    info->busdev.qdev.reset = apic_reset_common;
-    info->busdev.qdev.no_user = 1;
-    info->busdev.qdev.props = apic_properties_common;
-    sysbus_register_withprop(&info->busdev);
+    info->size = sizeof(APICCommonState),
+    info->vmsd = &vmstate_apic_common;
+    info->reset = apic_reset_common;
+    info->no_user = 1;
+    info->props = apic_properties_common;
+    sysbus_qdev_register_subclass(info, TYPE_APIC_COMMON);
 }
+
+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
index 1db4f06..1c6971c 100644
--- a/hw/apic_internal.h
+++ b/hw/apic_internal.h
@@ -67,6 +67,25 @@
 
 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;
@@ -97,19 +116,8 @@ struct APICCommonState {
     int wait_for_sipi;
 };
 
-typedef struct APICCommonInfo APICCommonInfo;
-
-struct APICCommonInfo {
-    SysBusDeviceInfo busdev;
-    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);
-};
-
 void apic_report_irq_delivered(int delivered);
-void apic_qdev_register(APICCommonInfo *info);
+void apic_qdev_register(DeviceInfo *info);
 bool apic_next_timer(APICCommonState *s, int64_t current_time);
 
 #endif /* !QEMU_APIC_INTERNAL_H */
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index f4d88dc..53c5408 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -201,33 +201,51 @@ 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),
-        /* 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 void mpcore_rirq_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = realview_mpcore_init;
+}
+
+static DeviceInfo mpcore_rirq_info = {
+    .name = "realview_mpcore",
+    .size = sizeof(mpcore_rirq_state),
+    .props = mpcore_rirq_properties,
+    .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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mpcore_priv_init;
+}
+
+static DeviceInfo mpcore_priv_info = {
+    .name = "arm11mpcore_priv",
+    .size = sizeof(mpcore_priv_state),
+    .props = mpcore_priv_properties,
+    .class_init = mpcore_priv_class_init,
 };
 
 static void arm11mpcore_register_devices(void)
diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c
index 2faed39..7c5fe32 100644
--- a/hw/arm_l2x0.c
+++ b/hw/arm_l2x0.c
@@ -160,22 +160,29 @@ 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[]) {
+static void l2x0_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = l2x0_priv_init;
+}
+
+static DeviceInfo l2x0_info = {
+    .name = "l2x0",
+    .size = sizeof(l2x0_state),
+    .vmsd = &vmstate_l2x0,
+    .no_user = 1,
+    .props = (Property[]) {
         DEFINE_PROP_UINT32("type", l2x0_state, cache_type, 0x1c100100),
         DEFINE_PROP_END_OF_LIST(),
     },
-    .qdev.reset = l2x0_priv_reset,
+    .reset = l2x0_priv_reset,
+    .class_init = l2x0_class_init,
 };
 
 static void l2x0_register_device(void)
 {
-    sysbus_register_withprop(&l2x0_info);
+    sysbus_qdev_register(&l2x0_info);
 }
 
 device_init(l2x0_register_device)
diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c
index 455a0aa..06319c2 100644
--- a/hw/arm_mptimer.c
+++ b/hw/arm_mptimer.c
@@ -311,14 +311,21 @@ 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[]) {
+static void arm_mptimer_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = arm_mptimer_init;
+}
+
+static DeviceInfo arm_mptimer_info = {
+    .name = "arm_mptimer",
+    .size = sizeof(arm_mptimer_state),
+    .vmsd = &vmstate_arm_mptimer,
+    .reset = arm_mptimer_reset,
+    .no_user = 1,
+    .class_init = arm_mptimer_class_init,
+    .props = (Property[]) {
         DEFINE_PROP_UINT32("num-cpu", arm_mptimer_state, num_cpu, 0),
         DEFINE_PROP_END_OF_LIST()
     }
diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index 4b88648..08fb443 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -401,17 +401,26 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = arm_sysctl_init1;
+}
+
+static DeviceInfo arm_sysctl_info = {
+    .name = "realview_sysctl",
+    .size = sizeof(arm_sysctl_state),
+    .vmsd = &vmstate_arm_sysctl,
+    .reset = arm_sysctl_reset,
+    .props = arm_sysctl_properties,
+    .class_init = arm_sysctl_class_init,
 };
 
 static void arm_sysctl_register_devices(void)
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index ead2535..15eb37c 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -283,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 {
@@ -358,10 +347,41 @@ 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 DeviceInfo icp_pit_info = {
+    .name = "integrator_pit",
+    .size = sizeof(icp_pit_state),
+    .class_init = icp_pit_class_init,
+};
+
+static void sp804_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = sp804_init;
+}
+
+static DeviceInfo sp804_info = {
+    .name = "sp804",
+    .size = sizeof(sp804_state),
+    .class_init = sp804_class_init,
+    .props = (Property[]) {
+        DEFINE_PROP_UINT32("freq0", sp804_state, freq0, 1000000),
+        DEFINE_PROP_UINT32("freq1", sp804_state, freq1, 1000000),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
 static void arm_timer_register_devices(void)
 {
-    sysbus_register_dev("integrator_pit", sizeof(icp_pit_state), icp_pit_init);
-    sysbus_register_withprop(&sp804_info);
+    sysbus_qdev_register(&icp_pit_info);
+    sysbus_qdev_register(&sp804_info);
 }
 
 device_init(arm_timer_register_devices)
diff --git a/hw/armv7m.c b/hw/armv7m.c
index 5c7a950..884fc90 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -245,14 +245,23 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = bitband_init;
+}
+
+static DeviceInfo bitband_info = {
+    .name = "ARM,bitband-memory",
+    .size = sizeof(BitBandState),
+    .props = bitband_properties,
+    .class_init = bitband_class_init,
 };
 
 static void armv7m_register_devices(void)
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index 28f36ba..2bb94e8 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -391,12 +391,19 @@ static int armv7m_nvic_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo armv7m_nvic_priv_info = {
-    .init = armv7m_nvic_init,
-    .qdev.name  = "armv7m_nvic",
-    .qdev.size  = sizeof(nvic_state),
-    .qdev.vmsd  = &vmstate_nvic,
-    .qdev.props = (Property[]) {
+static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = armv7m_nvic_init;
+}
+
+static DeviceInfo armv7m_nvic_priv_info = {
+    .name = "armv7m_nvic",
+    .size = sizeof(nvic_state),
+    .vmsd  = &vmstate_nvic,
+    .class_init = armv7m_nvic_class_init,
+    .props = (Property[]) {
         /* 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.
@@ -408,7 +415,7 @@ static SysBusDeviceInfo armv7m_nvic_priv_info = {
 
 static void armv7m_nvic_register_devices(void)
 {
-    sysbus_register_withprop(&armv7m_nvic_priv_info);
+    sysbus_qdev_register(&armv7m_nvic_priv_info);
 }
 
 device_init(armv7m_nvic_register_devices)
diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c
index 93fb2ed..da9e5cf 100644
--- a/hw/bitbang_i2c.c
+++ b/hw/bitbang_i2c.c
@@ -221,11 +221,18 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = gpio_i2c_init;
+}
+
+static DeviceInfo gpio_i2c_info = {
+    .name = "gpio_i2c",
+    .desc = "Virtual GPIO to I2C bridge",
+    .size = sizeof(GPIOI2CState),
+    .class_init = gpio_i2c_class_init,
 };
 
 static void bitbang_i2c_register(void)
diff --git a/hw/bonito.c b/hw/bonito.c
index 23384ec..0333a2e 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -786,11 +786,18 @@ static DeviceInfo bonito_info = {
     .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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = bonito_pcihost_initfn;
+}
+
+static DeviceInfo bonito_pcihost_info = {
+    .name = "Bonito-pcihost",
+    .size = sizeof(BonitoState),
+    .no_user = 1,
+    .class_init = bonito_pcihost_class_init,
 };
 
 static void bonito_register(void)
diff --git a/hw/container.c b/hw/container.c
index 9cbf399..73f94c5 100644
--- a/hw/container.c
+++ b/hw/container.c
@@ -5,11 +5,18 @@ 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_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = container_initfn;
+}
+
+static DeviceInfo container_info = {
+    .name = "container",
+    .size = sizeof(SysBusDevice),
+    .no_user = 1,
+    .class_init = container_class_init,
 };
 
 static void container_init(void)
diff --git a/hw/cs4231.c b/hw/cs4231.c
index 2dfb708..87c4eb9 100644
--- a/hw/cs4231.c
+++ b/hw/cs4231.c
@@ -151,15 +151,24 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = cs4231_init1;
+}
+
+static DeviceInfo cs4231_info = {
+    .name = "SUNW,CS4231",
+    .size = sizeof(CSState),
+    .vmsd = &vmstate_cs4231,
+    .reset = cs_reset,
+    .props = cs4231_properties,
+    .class_init = cs4231_class_init,
 };
 
 static void cs4231_register_devices(void)
diff --git a/hw/dec_pci.c b/hw/dec_pci.c
index 7c3f50e..f0ecaff 100644
--- a/hw/dec_pci.c
+++ b/hw/dec_pci.c
@@ -84,7 +84,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;
 
@@ -123,11 +123,22 @@ static DeviceInfo dec_21154_pci_host_info = {
     .class_init = dec_21154_pci_host_class_init,
 };
 
-static void dec_register_devices(void)
+static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data)
 {
-    sysbus_register_dev("dec-21154", sizeof(DECState),
-                        pci_dec_21154_init_device);
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = pci_dec_21154_device_init;
+}
+
+static DeviceInfo pci_dec_21154_device_info = {
+    .name = "dec-21154",
+    .size = sizeof(DECState),
+    .class_init = pci_dec_21154_device_class_init,
+};
 
+static void dec_register_devices(void)
+{
+    sysbus_qdev_register(&pci_dec_21154_device_info);
     pci_qdev_register(&dec_21154_pci_host_info);
     pci_qdev_register(&dec_21154_pci_bridge_info);
 }
diff --git a/hw/ds1225y.c b/hw/ds1225y.c
index 7aa0832..5890b16 100644
--- a/hw/ds1225y.c
+++ b/hw/ds1225y.c
@@ -134,16 +134,25 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = nvram_sysbus_initfn;
+}
+
+static DeviceInfo nvram_sysbus_info = {
+    .name = "ds1225y",
+    .size = sizeof(SysBusNvRamState),
+    .vmsd = &vmstate_nvram,
+    .props = nvram_sysbus_properties,
+    .class_init = nvram_sysbus_class_init,
 };
 
 static void nvram_register(void)
diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c
index 7743465..2d82c48 100644
--- a/hw/eccmemctl.c
+++ b/hw/eccmemctl.c
@@ -308,16 +308,25 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = ecc_init1;
+}
+
+static DeviceInfo ecc_info = {
+    .name = "eccmemctl",
+    .size = sizeof(ECCState),
+    .vmsd = &vmstate_ecc,
+    .reset = ecc_reset,
+    .props = ecc_properties,
+    .class_init = ecc_class_init,
 };
 
 
diff --git a/hw/empty_slot.c b/hw/empty_slot.c
index 8b734f2..70e45d0 100644
--- a/hw/empty_slot.c
+++ b/hw/empty_slot.c
@@ -76,10 +76,17 @@ 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 DeviceInfo empty_slot_info = {
+    .name = "empty_slot",
+    .size = sizeof(EmptySlot),
+    .class_init = empty_slot_class_init,
 };
 
 static void empty_slot_register_devices(void)
diff --git a/hw/escc.c b/hw/escc.c
index 81204a6..d905d96 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -901,23 +901,32 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = escc_init1;
+}
+
+static DeviceInfo escc_info = {
+    .name = "escc",
+    .size = sizeof(SerialState),
+    .vmsd = &vmstate_escc,
+    .reset = escc_reset,
+    .props = escc_properties,
+    .class_init = escc_class_init,
 };
 
 static void escc_register_devices(void)
diff --git a/hw/esp.c b/hw/esp.c
index 9551c78..71d3e70 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -753,15 +753,24 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = esp_init1;
+}
+
+static DeviceInfo esp_info = {
+    .name = "esp",
+    .size = sizeof(ESPState),
+    .vmsd = &vmstate_esp,
+    .reset = esp_hard_reset,
+    .props = esp_properties,
+    .class_init = esp_class_init,
 };
 
 static void esp_register_devices(void)
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index 1b6b71d..92c822b 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -613,17 +613,26 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = fs_eth_init;
+}
+
+static DeviceInfo etraxfs_eth_info = {
+    .name = "etraxfs-eth",
+    .size = sizeof(struct fs_eth),
+    .props = etraxfs_eth_properties,
+    .class_init = etraxfs_eth_class_init,
 };
 
 static void etraxfs_eth_register(void)
diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c
index 993d6a8..8acf01e 100644
--- a/hw/etraxfs_pic.c
+++ b/hw/etraxfs_pic.c
@@ -151,14 +151,23 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = etraxfs_pic_init;
+}
+
+static DeviceInfo etraxfs_pic_info = {
+    .name = "etraxfs,pic",
+    .size = sizeof(struct etrax_pic),
+    .props = etraxfs_pic_properties,
+    .class_init = etraxfs_pic_class_init,
 };
 
 static void etraxfs_pic_register(void)
diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c
index 2623dab..a487805 100644
--- a/hw/etraxfs_ser.c
+++ b/hw/etraxfs_ser.c
@@ -224,11 +224,18 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = etraxfs_ser_init;
+}
+
+static DeviceInfo etraxfs_ser_info = {
+    .name = "etraxfs,serial",
+    .size = sizeof(struct etrax_serial),
+    .reset = etraxfs_ser_reset,
+    .class_init = etraxfs_ser_class_init,
 };
 
 static void etraxfs_serial_register(void)
diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
index 2dfdb30..c33058c 100644
--- a/hw/etraxfs_timer.c
+++ b/hw/etraxfs_timer.c
@@ -329,10 +329,22 @@ 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 DeviceInfo etraxfs_timer_info = {
+    .name = "etraxfs,timer",
+    .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);
+    sysbus_qdev_register(&etraxfs_timer_info);
 }
 
 device_init(etraxfs_timer_register)
diff --git a/hw/fdc.c b/hw/fdc.c
index f761221..8562284 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1992,29 +1992,47 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sysbus_fdc_init1;
+}
+
+static DeviceInfo sysbus_fdc_info = {
+    .name = "sysbus-fdc",
+    .size = sizeof(FDCtrlSysBus),
+    .vmsd = &vmstate_sysbus_fdc,
+    .reset = fdctrl_external_reset_sysbus,
+    .props = sysbus_fdc_properties,
+    .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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sun4m_fdc_init1;
+}
+
+static DeviceInfo sun4m_fdc_info = {
+    .name = "SUNW,fdtwo",
+    .size = sizeof(FDCtrlSysBus),
+    .vmsd = &vmstate_sysbus_fdc,
+    .reset = fdctrl_external_reset_sysbus,
+    .props = sun4m_fdc_properties,
+    .class_init = sun4m_fdc_class_init,
 };
 
 static void fdc_register_devices(void)
diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c
index f953532..e669ed4 100644
--- a/hw/fw_cfg.c
+++ b/hw/fw_cfg.c
@@ -531,18 +531,27 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = fw_cfg_init1;
+}
+
+static DeviceInfo fw_cfg_info = {
+    .name = "fw_cfg",
+    .size = sizeof(FWCfgState),
+    .vmsd = &vmstate_fw_cfg,
+    .reset = fw_cfg_reset,
+    .no_user = 1,
+    .props = fw_cfg_properties,
+    .class_init = fw_cfg_class_init,
 };
 
 static void fw_cfg_register_devices(void)
diff --git a/hw/g364fb.c b/hw/g364fb.c
index 02ec7b5..82b31f7 100644
--- a/hw/g364fb.c
+++ b/hw/g364fb.c
@@ -548,18 +548,27 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = g364fb_sysbus_init;
+}
+
+static DeviceInfo g364fb_sysbus_info = {
+    .name = "sysbus-g364",
+    .desc = "G364 framebuffer",
+    .size = sizeof(G364SysBusState),
+    .vmsd = &vmstate_g364fb,
+    .reset = g364fb_sysbus_reset,
+    .props = g364fb_sysbus_properties,
+    .class_init = g364fb_sysbus_class_init,
 };
 
 static void g364fb_register(void)
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index a790f97..549859d 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -139,16 +139,23 @@ static DeviceInfo grackle_pci_info = {
     .class_init = grackle_pci_class_init,
 };
 
-static SysBusDeviceInfo grackle_pci_host_info = {
-    .qdev.name = "grackle-pcihost",
-    .qdev.size = sizeof(GrackleState),
-    .qdev.no_user = 1,
-    .init = pci_grackle_init_device,
+static void pci_grackle_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pci_grackle_init_device;
+}
+
+static DeviceInfo grackle_pci_host_info = {
+    .name = "grackle-pcihost",
+    .size = sizeof(GrackleState),
+    .no_user = 1,
+    .class_init = pci_grackle_class_init,
 };
 
 static void grackle_register_devices(void)
 {
-    sysbus_register_withprop(&grackle_pci_host_info);
+    sysbus_qdev_register(&grackle_pci_host_info);
     pci_qdev_register(&grackle_pci_info);
 }
 
diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
index f8a64e1..dc12d58 100644
--- a/hw/grlib_apbuart.c
+++ b/hw/grlib_apbuart.c
@@ -170,14 +170,23 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = grlib_apbuart_init;
+}
+
+static DeviceInfo grlib_gptimer_info = {
+    .name = "grlib,apbuart",
+    .size = sizeof(UART),
+    .props = grlib_gptimer_properties,
+    .class_init = grlib_gptimer_class_init,
 };
 
 static void grlib_gptimer_register(void)
diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c
index 9c98a83..219009e 100644
--- a/hw/grlib_gptimer.c
+++ b/hw/grlib_gptimer.c
@@ -372,17 +372,26 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = grlib_gptimer_init;
+}
+
+static DeviceInfo grlib_gptimer_info = {
+    .name = "grlib,gptimer",
+    .reset = grlib_gptimer_reset,
+    .size = sizeof(GPTimerUnit),
+    .props = grlib_gptimer_properties,
+    .class_init = grlib_gptimer_class_init,
 };
 
 static void grlib_gptimer_register(void)
diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c
index 2872556..1ccddfb 100644
--- a/hw/grlib_irqmp.c
+++ b/hw/grlib_irqmp.c
@@ -354,16 +354,25 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = grlib_irqmp_init;
+}
+
+static DeviceInfo grlib_irqmp_info = {
+    .name = "grlib,irqmp",
+    .reset = grlib_irqmp_reset,
+    .size = sizeof(IRQMP),
+    .props = grlib_irqmp_properties,
+    .class_init = grlib_irqmp_class_init,
 };
 
 static void grlib_irqmp_register(void)
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index 9fc51f2..79d2dfb 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -1153,10 +1153,22 @@ static DeviceInfo gt64120_pci_info = {
     .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 DeviceInfo gt64120_info = {
+    .name = "gt64120",
+    .size = sizeof(GT64120State),
+    .class_init = gt64120_class_init,
+};
+
 static void gt64120_pci_register_devices(void)
 {
-    sysbus_register_dev("gt64120", sizeof(GT64120State),
-                        gt64120_init);
+    sysbus_qdev_register(&gt64120_info);
     pci_qdev_register(&gt64120_pci_info);
 }
 
diff --git a/hw/highbank.c b/hw/highbank.c
index 136297c..9f76716 100644
--- a/hw/highbank.c
+++ b/hw/highbank.c
@@ -159,18 +159,25 @@ static int highbank_regs_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo highbank_regs_info = {
-    .init       = highbank_regs_init,
-    .qdev.name  = "highbank-regs",
-    .qdev.desc  = "Calxeda Highbank registers",
-    .qdev.size  = sizeof(HighbankRegsState),
-    .qdev.vmsd  = &vmstate_highbank_regs,
-    .qdev.reset = highbank_regs_reset,
+static void highbank_regs_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = highbank_regs_init;
+}
+
+static DeviceInfo highbank_regs_info = {
+    .name  = "highbank-regs",
+    .desc  = "Calxeda Highbank registers",
+    .size  = sizeof(HighbankRegsState),
+    .vmsd  = &vmstate_highbank_regs,
+    .class_init = highbank_regs_class_init,
+    .reset = highbank_regs_reset,
 };
 
 static void highbank_regs_register_device(void)
 {
-    sysbus_register_withprop(&highbank_regs_info);
+    sysbus_qdev_register(&highbank_regs_info);
 }
 
 device_init(highbank_regs_register_device)
diff --git a/hw/hpet.c b/hw/hpet.c
index 5312df7..aba9ea9 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -695,18 +695,27 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = hpet_init;
+}
+
+static DeviceInfo hpet_device_info = {
+    .name = "hpet",
+    .size = sizeof(HPETState),
+    .no_user = 1,
+    .vmsd = &vmstate_hpet,
+    .reset = hpet_reset,
+    .props = hpet_device_properties,
+    .class_init = hpet_device_class_init,
 };
 
 static void hpet_register_device(void)
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 0309dd6..8869fd6 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -1239,22 +1239,27 @@ static int sysbus_ahci_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo sysbus_ahci_info = {
-    .qdev.name    = "sysbus-ahci",
-    .qdev.size    = sizeof(SysbusAHCIState),
-    .qdev.vmsd    = &vmstate_sysbus_ahci,
-    .qdev.props = (Property[]) {
+static void sysbus_ahci_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = sysbus_ahci_init;
+}
+
+static DeviceInfo sysbus_ahci_info = {
+    .name    = "sysbus-ahci",
+    .size    = sizeof(SysbusAHCIState),
+    .vmsd    = &vmstate_sysbus_ahci,
+    .class_init = sysbus_ahci_class_init,
+    .props = (Property[]) {
         DEFINE_PROP_UINT32("num-ports", SysbusAHCIState, num_ports, 1),
         DEFINE_PROP_END_OF_LIST(),
     },
-    .init         = sysbus_ahci_init,
-
-
 };
 
 static void sysbus_ahci_register(void)
 {
-    sysbus_register_withprop(&sysbus_ahci_info);
+    sysbus_qdev_register(&sysbus_ahci_info);
 }
 
 device_init(sysbus_ahci_register);
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index e5712fc..130accf 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -518,19 +518,41 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = integratorcm_init;
+}
+
+static DeviceInfo core_info = {
+    .name = "integrator_core",
+    .size = sizeof(integratorcm_state),
+    .props = core_properties,
+    .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 DeviceInfo icp_pic_info = {
+    .name = "integrator_pic",
+    .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_qdev_register(&icp_pic_info);
     sysbus_register_withprop(&core_info);
 }
 
diff --git a/hw/ioapic.c b/hw/ioapic.c
index 0c8be50..0939009 100644
--- a/hw/ioapic.c
+++ b/hw/ioapic.c
@@ -235,11 +235,18 @@ static void ioapic_init(IOAPICCommonState *s, int instance_no)
     ioapics[instance_no] = s;
 }
 
-static IOAPICCommonInfo ioapic_info = {
-    .busdev.qdev.name = "ioapic",
-    .busdev.qdev.size = sizeof(IOAPICCommonState),
-    .busdev.qdev.reset = ioapic_reset_common,
-    .init = ioapic_init,
+static void ioapic_class_init(ObjectClass *klass, void *data)
+{
+    IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
+
+    k->init = ioapic_init;
+}
+
+static DeviceInfo ioapic_info = {
+    .name = "ioapic",
+    .size = sizeof(IOAPICCommonState),
+    .reset = ioapic_reset_common,
+    .class_init = ioapic_class_init,
 };
 
 static void ioapic_register_devices(void)
diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c
index 4a7624c..4bb7ea9 100644
--- a/hw/ioapic_common.c
+++ b/hw/ioapic_common.c
@@ -25,7 +25,7 @@
 
 void ioapic_reset_common(DeviceState *dev)
 {
-    IOAPICCommonState *s = DO_UPCAST(IOAPICCommonState, busdev.qdev, dev);
+    IOAPICCommonState *s = IOAPIC_COMMON(dev);
     int i;
 
     s->id = 0;
@@ -38,9 +38,8 @@ void ioapic_reset_common(DeviceState *dev)
 
 static void ioapic_dispatch_pre_save(void *opaque)
 {
-    IOAPICCommonState *s = opaque;
-    IOAPICCommonInfo *info =
-        DO_UPCAST(IOAPICCommonInfo, busdev.qdev, qdev_get_info(&s->busdev.qdev));
+    IOAPICCommonState *s = IOAPIC_COMMON(opaque);
+    IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
 
     if (info->pre_save) {
         info->pre_save(s);
@@ -49,9 +48,8 @@ static void ioapic_dispatch_pre_save(void *opaque)
 
 static int ioapic_dispatch_post_load(void *opaque, int version_id)
 {
-    IOAPICCommonState *s = opaque;
-    IOAPICCommonInfo *info =
-        DO_UPCAST(IOAPICCommonInfo, busdev.qdev, qdev_get_info(&s->busdev.qdev));
+    IOAPICCommonState *s = IOAPIC_COMMON(opaque);
+    IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
 
     if (info->post_load) {
         info->post_load(s);
@@ -62,14 +60,14 @@ static int ioapic_dispatch_post_load(void *opaque, int version_id)
 static int ioapic_init_common(SysBusDevice *dev)
 {
     IOAPICCommonState *s = FROM_SYSBUS(IOAPICCommonState, dev);
-    IOAPICCommonInfo *info;
+    IOAPICCommonClass *info;
     static int ioapic_no;
 
     if (ioapic_no >= MAX_IOAPICS) {
         return -1;
     }
 
-    info = DO_UPCAST(IOAPICCommonInfo, busdev.qdev, qdev_get_info(&s->busdev.qdev));
+    info = IOAPIC_COMMON_GET_CLASS(s);
     info->init(s, ioapic_no);
 
     sysbus_init_mmio(&s->busdev, &s->io_memory);
@@ -95,10 +93,33 @@ static const VMStateDescription vmstate_ioapic_common = {
     }
 };
 
-void ioapic_qdev_register(IOAPICCommonInfo *info)
+static void ioapic_common_class_init(ObjectClass *klass, void *data)
 {
-    info->busdev.init = ioapic_init_common;
-    info->busdev.qdev.vmsd = &vmstate_ioapic_common;
-    info->busdev.qdev.no_user = 1;
-    sysbus_register_withprop(&info->busdev);
+    SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sc->init = ioapic_init_common;
+}
+
+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,
+};
+
+void ioapic_qdev_register(DeviceInfo *info)
+{
+    info->vmsd = &vmstate_ioapic_common;
+    info->no_user = 1;
+    sysbus_qdev_register_subclass(info, TYPE_IOAPIC_COMMON);
 }
+
+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
index f8d90c0..9dff1a7 100644
--- a/hw/ioapic_internal.h
+++ b/hw/ioapic_internal.h
@@ -73,6 +73,21 @@
 
 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;
@@ -82,16 +97,7 @@ struct IOAPICCommonState {
     uint64_t ioredtbl[IOAPIC_NUM_PINS];
 };
 
-typedef struct IOAPICCommonInfo IOAPICCommonInfo;
-
-struct IOAPICCommonInfo {
-    SysBusDeviceInfo busdev;
-    void (*init)(IOAPICCommonState *s, int instance_no);
-    void (*pre_save)(IOAPICCommonState *s);
-    void (*post_load)(IOAPICCommonState *s);
-};
-
-void ioapic_qdev_register(IOAPICCommonInfo *info);
+void ioapic_qdev_register(DeviceInfo *info);
 void ioapic_reset_common(DeviceState *dev);
 
 #endif /* !QEMU_IOAPIC_INTERNAL_H */
diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index 6943194..92d8882 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -189,12 +189,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = isabus_bridge_init;
+}
+
+static DeviceInfo isabus_bridge_info = {
+    .name = "isabus-bridge",
+    .fw_name = "isa",
+    .size = sizeof(SysBusDevice),
+    .no_user = 1,
+    .class_init = isabus_bridge_class_init,
 };
 
 static TypeInfo isa_device_type_info = {
diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c
index 6300695..bc80ae4 100644
--- a/hw/kvm/apic.c
+++ b/hw/kvm/apic.c
@@ -122,12 +122,19 @@ static void kvm_apic_init(APICCommonState *s)
                                    MSI_SPACE_SIZE);
 }
 
-static APICCommonInfo kvm_apic_info = {
-    .busdev.qdev.name = "kvm-apic",
-    .init = kvm_apic_init,
-    .set_base = kvm_apic_set_base,
-    .set_tpr = kvm_apic_set_tpr,
-    .external_nmi = kvm_apic_external_nmi,
+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 DeviceInfo kvm_apic_info = {
+    .name = "kvm-apic",
+    .class_init = kvm_apic_class_init,
 };
 
 static void kvm_apic_register_device(void)
diff --git a/hw/kvm/clock.c b/hw/kvm/clock.c
index bb28c08..b997d2a 100644
--- a/hw/kvm/clock.c
+++ b/hw/kvm/clock.c
@@ -92,12 +92,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = kvmclock_init;
+}
+
+static DeviceInfo kvmclock_info = {
+    .name = "kvmclock",
+    .size = sizeof(KVMClockState),
+    .vmsd = &kvmclock_vmsd,
+    .no_user = 1,
+    .class_init = kvmclock_class_init,
 };
 
 /* Note: Must be called after VCPU initialization. */
diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c
index 10ffdd4..f8ea0cc 100644
--- a/hw/kvm/ioapic.c
+++ b/hw/kvm/ioapic.c
@@ -93,17 +93,24 @@ static void kvm_ioapic_init(IOAPICCommonState *s, int instance_no)
     qdev_init_gpio_in(&s->busdev.qdev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS);
 }
 
-static IOAPICCommonInfo kvm_ioapic_info = {
-    .busdev.qdev.name  = "kvm-ioapic",
-    .busdev.qdev.size = sizeof(KVMIOAPICState),
-    .busdev.qdev.reset = kvm_ioapic_reset,
-    .busdev.qdev.props = (Property[]) {
+static void kvm_ioapic_class_init(ObjectClass *klass, void *data)
+{
+    IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
+
+    k->init      = kvm_ioapic_init;
+    k->pre_save  = kvm_ioapic_get;
+    k->post_load = kvm_ioapic_put;
+}
+
+static DeviceInfo kvm_ioapic_info = {
+    .name  = "kvm-ioapic",
+    .size = sizeof(KVMIOAPICState),
+    .reset = kvm_ioapic_reset,
+    .class_init = kvm_ioapic_class_init,
+    .props = (Property[]) {
         DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0),
         DEFINE_PROP_END_OF_LIST()
     },
-    .init      = kvm_ioapic_init,
-    .pre_save  = kvm_ioapic_get,
-    .post_load = kvm_ioapic_put,
 };
 
 static void kvm_ioapic_register_device(void)
diff --git a/hw/lan9118.c b/hw/lan9118.c
index 93e1896..3925b04 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -1238,16 +1238,25 @@ static int lan9118_init1(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo lan9118_info = {
-    .init = lan9118_init1,
-    .qdev.name  = "lan9118",
-    .qdev.size  = sizeof(lan9118_state),
-    .qdev.reset = lan9118_reset,
-    .qdev.vmsd = &vmstate_lan9118,
-    .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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lan9118_init1;
+}
+
+static DeviceInfo lan9118_info = {
+    .name = "lan9118",
+    .size = sizeof(lan9118_state),
+    .reset = lan9118_reset,
+    .vmsd = &vmstate_lan9118,
+    .props = lan9118_properties,
+    .class_init = lan9118_class_init,
 };
 
 static void lan9118_register_devices(void)
diff --git a/hw/lance.c b/hw/lance.c
index 7164700..969d766 100644
--- a/hw/lance.c
+++ b/hw/lance.c
@@ -137,18 +137,27 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lance_init;
+}
+
+static DeviceInfo lance_info = {
+    .name = "lance",
+    .fw_name = "ethernet",
+    .size = sizeof(SysBusPCNetState),
+    .reset = lance_reset,
+    .vmsd = &vmstate_lance,
+    .props = lance_properties,
+    .class_init = lance_class_init,
 };
 
 static void lance_register_devices(void)
diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c
index 5454aa4..e25a409 100644
--- a/hw/lm32_juart.c
+++ b/hw/lm32_juart.c
@@ -134,12 +134,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lm32_juart_init;
+}
+
+static DeviceInfo lm32_juart_info = {
+    .name = "lm32-juart",
+    .size = sizeof(LM32JuartState),
+    .vmsd = &vmstate_lm32_juart,
+    .reset = juart_reset,
+    .class_init = lm32_juart_class_init,
 };
 
 static void lm32_juart_register(void)
diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c
index 8dd0050..b7b1886 100644
--- a/hw/lm32_pic.c
+++ b/hw/lm32_pic.c
@@ -174,12 +174,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lm32_pic_init;
+}
+
+static DeviceInfo lm32_pic_info = {
+    .name = "lm32-pic",
+    .size = sizeof(LM32PicState),
+    .vmsd = &vmstate_lm32_pic,
+    .reset = pic_reset,
+    .class_init = lm32_pic_class_init,
 };
 
 static void lm32_pic_register(void)
diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c
index 83974ee..c83809e 100644
--- a/hw/lm32_sys.c
+++ b/hw/lm32_sys.c
@@ -141,16 +141,25 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lm32_sys_init;
+}
+
+static DeviceInfo lm32_sys_info = {
+    .name = "lm32-sys",
+    .size = sizeof(LM32SysState),
+    .vmsd = &vmstate_lm32_sys,
+    .reset = sys_reset,
+    .props = lm32_sys_properties,
+    .class_init = lm32_sys_class_init,
 };
 
 static void lm32_sys_register(void)
diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c
index 115e1e9..932c1f0 100644
--- a/hw/lm32_timer.c
+++ b/hw/lm32_timer.c
@@ -199,18 +199,25 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lm32_timer_init;
+}
+
+static DeviceInfo lm32_timer_info = {
+    .name = "lm32-timer",
+    .size = sizeof(LM32TimerState),
+    .vmsd = &vmstate_lm32_timer,
+    .reset = timer_reset,
+    .props = lm32_timer_properties,
+    .class_init = lm32_timer_class_init,
 };
 
 static void lm32_timer_register(void)
diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c
index d013abd..ea7d00e 100644
--- a/hw/lm32_uart.c
+++ b/hw/lm32_uart.c
@@ -271,12 +271,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lm32_uart_init;
+}
+
+static DeviceInfo lm32_uart_info = {
+    .name = "lm32-uart",
+    .size = sizeof(LM32UartState),
+    .vmsd = &vmstate_lm32_uart,
+    .reset = uart_reset,
+    .class_init = lm32_uart_class_init,
 };
 
 static void lm32_uart_register(void)
diff --git a/hw/m48t59.c b/hw/m48t59.c
index 5912cd6..262cfb8 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -740,17 +740,26 @@ static DeviceInfo m48t59_isa_info = {
     }
 };
 
-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 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = m48t59_init1;
+}
+
+static DeviceInfo m48t59_info = {
+    .name = "m48t59",
+    .size = sizeof(M48t59SysBusState),
+    .reset = m48t59_reset_sysbus,
+    .props = m48t59_properties,
+    .class_init = m48t59_class_init,
 };
 
 static void m48t59_register_devices(void)
diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c
index 409b1eb..355e492 100644
--- a/hw/marvell_88w8618_audio.c
+++ b/hw/marvell_88w8618_audio.c
@@ -272,16 +272,25 @@ 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[]) {
-        DEFINE_PROP_PTR("wm8750", 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mv88w8618_audio_init;
+}
+
+static DeviceInfo mv88w8618_audio_info = {
+    .name = "mv88w8618_audio",
+    .size = sizeof(mv88w8618_audio_state),
+    .reset = mv88w8618_audio_reset,
+    .vmsd = &mv88w8618_audio_vmsd,
+    .props = mv88w8618_audio_properties,
+    .class_init = mv88w8618_audio_class_init,
 };
 
 static void mv88w8618_register_devices(void)
diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c
index e824a49..7dce5bc 100644
--- a/hw/milkymist-ac97.c
+++ b/hw/milkymist-ac97.c
@@ -319,12 +319,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_ac97_init;
+}
+
+static DeviceInfo milkymist_ac97_info = {
+    .name = "milkymist-ac97",
+    .size = sizeof(MilkymistAC97State),
+    .vmsd = &vmstate_milkymist_ac97,
+    .reset = milkymist_ac97_reset,
+    .class_init = milkymist_ac97_class_init,
 };
 
 static void milkymist_ac97_register(void)
diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c
index be575c9..46e8ae6 100644
--- a/hw/milkymist-hpdmc.c
+++ b/hw/milkymist-hpdmc.c
@@ -145,12 +145,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_hpdmc_init;
+}
+
+static DeviceInfo milkymist_hpdmc_info = {
+    .name = "milkymist-hpdmc",
+    .size = sizeof(MilkymistHpdmcState),
+    .vmsd = &vmstate_milkymist_hpdmc,
+    .reset = milkymist_hpdmc_reset,
+    .class_init = milkymist_hpdmc_class_init,
 };
 
 static void milkymist_hpdmc_register(void)
diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c
index 865a46c..97eb793 100644
--- a/hw/milkymist-memcard.c
+++ b/hw/milkymist-memcard.c
@@ -278,12 +278,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_memcard_init;
+}
+
+static DeviceInfo milkymist_memcard_info = {
+    .name = "milkymist-memcard",
+    .size = sizeof(MilkymistMemcardState),
+    .vmsd = &vmstate_milkymist_memcard,
+    .reset = milkymist_memcard_reset,
+    .class_init = milkymist_memcard_class_init,
 };
 
 static void milkymist_memcard_register(void)
diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c
index 107ba65..1ac6c6a 100644
--- a/hw/milkymist-minimac2.c
+++ b/hw/milkymist-minimac2.c
@@ -516,19 +516,28 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_minimac2_init;
+}
+
+static DeviceInfo milkymist_minimac2_info = {
+    .name = "milkymist-minimac2",
+    .size = sizeof(MilkymistMinimac2State),
+    .vmsd = &vmstate_milkymist_minimac2,
+    .reset = milkymist_minimac2_reset,
+    .props = milkymist_minimac2_properties,
+    .class_init = milkymist_minimac2_class_init,
 };
 
 static void milkymist_minimac2_register(void)
diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c
index dc92eb6..b6ade5a 100644
--- a/hw/milkymist-pfpu.c
+++ b/hw/milkymist-pfpu.c
@@ -519,12 +519,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_pfpu_init;
+}
+
+static DeviceInfo milkymist_pfpu_info = {
+    .name = "milkymist-pfpu",
+    .size = sizeof(MilkymistPFPUState),
+    .vmsd = &vmstate_milkymist_pfpu,
+    .reset = milkymist_pfpu_reset,
+    .class_init = milkymist_pfpu_class_init,
 };
 
 static void milkymist_pfpu_register(void)
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
index 83bd1c4..f4d2dad 100644
--- a/hw/milkymist-softusb.c
+++ b/hw/milkymist-softusb.c
@@ -297,27 +297,28 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_softusb_init;
+}
+
+static DeviceInfo milkymist_softusb_info = {
+    .name = "milkymist-softusb",
+    .size = sizeof(MilkymistSoftUsbState),
+    .vmsd = &vmstate_milkymist_softusb,
+    .reset = milkymist_softusb_reset,
+    .props = milkymist_softusb_properties,
+    .class_init = milkymist_softusb_class_init,
 };
 
 static void milkymist_softusb_register(void)
diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c
index bd2a298..4b017fa 100644
--- a/hw/milkymist-sysctl.c
+++ b/hw/milkymist-sysctl.c
@@ -292,23 +292,32 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_sysctl_init;
+}
+
+static DeviceInfo milkymist_sysctl_info = {
+    .name = "milkymist-sysctl",
+    .size = sizeof(MilkymistSysctlState),
+    .vmsd = &vmstate_milkymist_sysctl,
+    .reset = milkymist_sysctl_reset,
+    .props = milkymist_sysctl_properties,
+    .class_init = milkymist_sysctl_class_init,
 };
 
 static void milkymist_sysctl_register(void)
diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c
index 20110e5..4004a12 100644
--- a/hw/milkymist-tmu2.c
+++ b/hw/milkymist-tmu2.c
@@ -465,12 +465,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_tmu2_init;
+}
+
+static DeviceInfo milkymist_tmu2_info = {
+    .name = "milkymist-tmu2",
+    .size = sizeof(MilkymistTMU2State),
+    .vmsd = &vmstate_milkymist_tmu2,
+    .reset = milkymist_tmu2_reset,
+    .class_init = milkymist_tmu2_class_init,
 };
 
 static void milkymist_tmu2_register(void)
diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c
index eaf1c0d..312976d 100644
--- a/hw/milkymist-uart.c
+++ b/hw/milkymist-uart.c
@@ -218,12 +218,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_uart_init;
+}
+
+static DeviceInfo milkymist_uart_info = {
+    .name = "milkymist-uart",
+    .size = sizeof(MilkymistUartState),
+    .vmsd = &vmstate_milkymist_uart,
+    .reset = milkymist_uart_reset,
+    .class_init = milkymist_uart_class_init,
 };
 
 static void milkymist_uart_register(void)
diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c
index 108115e..81d31fa 100644
--- a/hw/milkymist-vgafb.c
+++ b/hw/milkymist-vgafb.c
@@ -299,17 +299,26 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_vgafb_init;
+}
+
+static DeviceInfo milkymist_vgafb_info = {
+    .name = "milkymist-vgafb",
+    .size = sizeof(MilkymistVgafbState),
+    .vmsd = &vmstate_milkymist_vgafb,
+    .reset = milkymist_vgafb_reset,
+    .props = milkymist_vgafb_properties,
+    .class_init = milkymist_vgafb_class_init,
 };
 
 static void milkymist_vgafb_register(void)
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 4a4f76d..64603ce 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -1007,11 +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[]) {
+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 DeviceInfo mips_malta_device = {
+    .name  = "mips-malta",
+    .size  = sizeof(MaltaState),
+    .class_init = mips_malta_class_init,
+    .props = (Property[]) {
         DEFINE_PROP_END_OF_LIST(),
     }
 };
@@ -1026,7 +1033,7 @@ static QEMUMachine mips_malta_machine = {
 
 static void mips_malta_device_init(void)
 {
-    sysbus_register_withprop(&mips_malta_device);
+    sysbus_qdev_register(&mips_malta_device);
 }
 
 static void mips_malta_machine_init(void)
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index 0f80cfe..8cf9161 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -252,17 +252,26 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mipsnet_sysbus_init;
+}
+
+static DeviceInfo mipsnet_info = {
+    .name = "mipsnet",
+    .desc = "MIPS Simulator network device",
+    .size = sizeof(MIPSnetState),
+    .vmsd = &vmstate_mipsnet,
+    .reset = mipsnet_sysbus_reset,
+    .props = mipsnet_properties,
+    .class_init = mipsnet_class_init,
 };
 
 static void mipsnet_register_devices(void)
diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c
index f01b38c..ec6bb4f 100644
--- a/hw/mpc8544_guts.c
+++ b/hw/mpc8544_guts.c
@@ -121,10 +121,17 @@ 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 DeviceInfo mpc8544_guts_info = {
+    .name = "mpc8544-guts",
+    .size = sizeof(GutsState),
+    .class_init = mpc8544_guts_class_init,
 };
 
 static void mpc8544_guts_register(void)
diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c
index 8bfa5dd..513bfa6 100644
--- a/hw/mst_fpga.c
+++ b/hw/mst_fpga.c
@@ -238,12 +238,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mst_fpga_init;
+}
+
+static DeviceInfo mst_fpga_info = {
+    .name = "mainstone-fpga",
+    .desc = "Mainstone II FPGA",
+    .size = sizeof(mst_irq_state),
+    .vmsd = &vmstate_mst_fpga_regs,
+    .class_init = mst_fpga_class_init,
 };
 
 static void mst_fpga_register(void)
diff --git a/hw/musicpal.c b/hw/musicpal.c
index bca5ee9..a2fc4bb 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -412,15 +412,24 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mv88w8618_eth_init;
+}
+
+static DeviceInfo mv88w8618_eth_info = {
+    .name = "mv88w8618_eth",
+    .size = sizeof(mv88w8618_eth_state),
+    .vmsd = &mv88w8618_eth_vmsd,
+    .props = mv88w8618_eth_properties,
+    .class_init = mv88w8618_eth_class_init,
 };
 
 /* LCD register offsets */
@@ -624,11 +633,18 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = musicpal_lcd_init;
+}
+
+static DeviceInfo musicpal_lcd_info = {
+    .name = "musicpal_lcd",
+    .size = sizeof(musicpal_lcd_state),
+    .vmsd = &musicpal_lcd_vmsd,
+    .class_init = musicpal_lcd_class_init,
 };
 
 /* PIC register offsets */
@@ -733,12 +749,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mv88w8618_pic_init;
+}
+
+static DeviceInfo mv88w8618_pic_info = {
+    .name = "mv88w8618_pic",
+    .size = sizeof(mv88w8618_pic_state),
+    .reset = mv88w8618_pic_reset,
+    .vmsd = &mv88w8618_pic_vmsd,
+    .class_init = mv88w8618_pic_class_init,
 };
 
 /* PIT register offsets */
@@ -901,12 +924,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mv88w8618_pit_init;
+}
+
+static DeviceInfo mv88w8618_pit_info = {
+    .name = "mv88w8618_pit",
+    .size = sizeof(mv88w8618_pit_state),
+    .reset = mv88w8618_pit_reset,
+    .vmsd = &mv88w8618_pit_vmsd,
+    .class_init = mv88w8618_pit_class_init,
 };
 
 /* Flash config register offsets */
@@ -973,11 +1003,18 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mv88w8618_flashcfg_init;
+}
+
+static DeviceInfo mv88w8618_flashcfg_info = {
+    .name = "mv88w8618_flashcfg",
+    .size = sizeof(mv88w8618_flashcfg_state),
+    .vmsd = &mv88w8618_flashcfg_vmsd,
+    .class_init = mv88w8618_flashcfg_class_init,
 };
 
 /* Misc register offsets */
@@ -1285,12 +1322,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = musicpal_gpio_init;
+}
+
+static DeviceInfo musicpal_gpio_info = {
+    .name = "musicpal_gpio",
+    .size = sizeof(musicpal_gpio_state),
+    .reset = musicpal_gpio_reset,
+    .vmsd = &musicpal_gpio_vmsd,
+    .class_init = musicpal_gpio_class_init,
 };
 
 /* Keyboard codes & masks */
@@ -1431,11 +1475,18 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = musicpal_key_init;
+}
+
+static DeviceInfo musicpal_key_info = {
+    .name = "musicpal_key",
+    .size = sizeof(musicpal_key_state),
+    .vmsd = &musicpal_key_vmsd,
+    .class_init = musicpal_key_class_init,
 };
 
 static struct arm_boot_info musicpal_binfo = {
@@ -1602,14 +1653,26 @@ 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 DeviceInfo mv88w8618_wlan_info = {
+    .name = "mv88w8618_wlan",
+    .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_qdev_register(&mv88w8618_wlan_info);
     sysbus_register_withprop(&musicpal_lcd_info);
     sysbus_register_withprop(&musicpal_gpio_info);
     sysbus_register_withprop(&musicpal_key_info);
diff --git a/hw/nand.c b/hw/nand.c
index 8597aa6..6248731 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -417,18 +417,27 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = nand_device_init;
+}
+
+static DeviceInfo nand_info = {
+    .name = "nand",
+    .size = sizeof(NANDFlashState),
+    .reset = nand_reset,
+    .vmsd = &vmstate_nand,
+    .props = nand_properties,
+    .class_init = nand_class_init,
 };
 
 static void nand_create_device(void)
diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c
index 29147be..97d2d93 100644
--- a/hw/omap_gpio.c
+++ b/hw/omap_gpio.c
@@ -731,34 +731,52 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = omap_gpio_init;
+}
+
+static DeviceInfo omap_gpio_info = {
+    .name = "omap-gpio",
+    .size = sizeof(struct omap_gpif_s),
+    .reset = omap_gpif_reset,
+    .props = omap_gpio_properties,
+    .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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = omap2_gpio_init;
+}
+
+static DeviceInfo omap2_gpio_info = {
+    .name = "omap2-gpio",
+    .size = sizeof(struct omap2_gpif_s),
+    .reset = omap2_gpif_reset,
+    .props = omap2_gpio_properties,
+    .class_init = omap2_gpio_class_init,
 };
 
 static void omap_gpio_register_device(void)
diff --git a/hw/omap_intc.c b/hw/omap_intc.c
index fc53ec7..310fe2d 100644
--- a/hw/omap_intc.c
+++ b/hw/omap_intc.c
@@ -373,16 +373,25 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = omap_intc_init;
+}
+
+static DeviceInfo omap_intc_info = {
+    .name = "omap-intc",
+    .size = sizeof(struct omap_intr_handler_s),
+    .reset = omap_inth_reset,
+    .props = omap_intc_properties,
+    .class_init = omap_intc_class_init,
 };
 
 static uint64_t omap2_inth_read(void *opaque, target_phys_addr_t addr,
@@ -604,18 +613,27 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = omap2_intc_init;
+}
+
+static DeviceInfo omap2_intc_info = {
+    .name = "omap2-intc",
+    .size = sizeof(struct omap_intr_handler_s),
+    .reset = omap_inth_reset,
+    .props = omap2_intc_properties,
+    .class_init = omap2_intc_class_init,
 };
 
 static void omap_intc_register_device(void)
diff --git a/hw/onenand.c b/hw/onenand.c
index 33c9718..e20d4d9 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -802,19 +802,28 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = onenand_initfn;
+}
+
+static DeviceInfo onenand_info = {
+    .name = "onenand",
+    .size = sizeof(OneNANDState),
+    .reset = onenand_system_reset,
+    .props = onenand_properties,
+    .class_init = onenand_class_init,
 };
 
 static void onenand_register_device(void)
diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c
index 5161b0c..1f45506 100644
--- a/hw/opencores_eth.c
+++ b/hw/opencores_eth.c
@@ -727,16 +727,25 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sysbus_open_eth_init;
+}
+
+static DeviceInfo open_eth_info = {
+    .name = "open_eth",
+    .desc = "Opencores 10/100 Mbit Ethernet",
+    .size = sizeof(OpenEthState),
+    .reset = qdev_open_eth_reset,
+    .props = open_eth_properties,
+    .class_init = open_eth_class_init,
 };
 
 static void open_eth_register_devices(void)
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 787db4e..8b01782 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -566,12 +566,19 @@ static DeviceInfo i440fx_info = {
     .class_init = i440fx_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_pcihost_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = i440fx_pcihost_initfn;
+}
+
+static DeviceInfo i440fx_pcihost_info = {
+    .name = "i440FX-pcihost",
+    .fw_name = "pci",
+    .size = sizeof(I440FXState),
+    .no_user = 1,
+    .class_init = i440fx_pcihost_class_init,
 };
 
 static void i440fx_register(void)
diff --git a/hw/pl011.c b/hw/pl011.c
index 1b05d76..088aa44 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -278,22 +278,46 @@ 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 DeviceInfo pl011_arm_info = {
+    .name = "pl011",
+    .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 DeviceInfo pl011_luminary_info = {
+    .name = "pl011_luminary",
+    .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);
+    sysbus_qdev_register(&pl011_arm_info);
+    sysbus_qdev_register(&pl011_luminary_info);
 }
 
 device_init(pl011_register_devices)
diff --git a/hw/pl022.c b/hw/pl022.c
index d43e4a2..4f62712 100644
--- a/hw/pl022.c
+++ b/hw/pl022.c
@@ -285,9 +285,22 @@ 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 DeviceInfo pl022_info = {
+    .name = "pl022",
+    .size = sizeof(pl022_state),
+    .class_init = pl022_class_init,
+};
+
 static void pl022_register_devices(void)
 {
-    sysbus_register_dev("pl022", sizeof(pl022_state), pl022_init);
+    sysbus_qdev_register(&pl022_info);
 }
 
 device_init(pl022_register_devices)
diff --git a/hw/pl031.c b/hw/pl031.c
index 2fb0c8e..4cb8528 100644
--- a/hw/pl031.c
+++ b/hw/pl031.c
@@ -213,12 +213,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl031_init;
+}
+
+static DeviceInfo pl031_info = {
+    .name = "pl031",
+    .size = sizeof(pl031_state),
+    .vmsd = &vmstate_pl031,
+    .no_user = 1,
+    .class_init = pl031_class_init,
 };
 
 static void pl031_register_devices(void)
diff --git a/hw/pl041.c b/hw/pl041.c
index 4585ccf..0482851 100644
--- a/hw/pl041.c
+++ b/hw/pl041.c
@@ -613,19 +613,27 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl041_init;
+}
+
+static DeviceInfo pl041_device_info = {
+    .name = "pl041",
+    .size = sizeof(pl041_state),
+    .vmsd = &vmstate_pl041,
+    .reset = pl041_device_reset,
+    .no_user = 1,
+    .props = pl041_device_properties,
+    .class_init = pl041_device_class_init,
 };
 
 static void pl041_register_device(void)
diff --git a/hw/pl050.c b/hw/pl050.c
index 8182a1c..5f60508 100644
--- a/hw/pl050.c
+++ b/hw/pl050.c
@@ -157,18 +157,32 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl050_init_keyboard;
+}
+
+static DeviceInfo pl050_kbd_info = {
+    .name = "pl050_keyboard",
+    .size = sizeof(pl050_state),
+    .vmsd = &vmstate_pl050,
+    .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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl050_init_mouse;
+}
+
+static DeviceInfo pl050_mouse_info = {
+    .name = "pl050_mouse",
+    .size = sizeof(pl050_state),
+    .vmsd = &vmstate_pl050,
+    .class_init = pl050_mouse_class_init,
 };
 
 static void pl050_register_devices(void)
diff --git a/hw/pl061.c b/hw/pl061.c
index f33ae84..9dc9406 100644
--- a/hw/pl061.c
+++ b/hw/pl061.c
@@ -293,18 +293,32 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl061_init_arm;
+}
+
+static DeviceInfo pl061_info = {
+    .name = "pl061",
+    .size = sizeof(pl061_state),
+    .vmsd = &vmstate_pl061,
+    .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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl061_init_luminary;
+}
+
+static DeviceInfo pl061_luminary_info = {
+    .name = "pl061_luminary",
+    .size = sizeof(pl061_state),
+    .vmsd = &vmstate_pl061,
+    .class_init = pl061_luminary_class_init,
 };
 
 static void pl061_register_devices(void)
diff --git a/hw/pl080.c b/hw/pl080.c
index e001df9..727bfa1 100644
--- a/hw/pl080.c
+++ b/hw/pl080.c
@@ -373,20 +373,34 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl080_init;
+}
+
+static DeviceInfo pl080_info = {
+    .name = "pl080",
+    .size = sizeof(pl080_state),
+    .vmsd = &vmstate_pl080,
+    .no_user = 1,
+    .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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl081_init;
+}
+
+static DeviceInfo pl081_info = {
+    .name = "pl081",
+    .size = sizeof(pl080_state),
+    .vmsd = &vmstate_pl080,
+    .no_user = 1,
+    .class_init = pl081_class_init,
 };
 
 /* The PL080 and PL081 are the same except for the number of channels
diff --git a/hw/pl110.c b/hw/pl110.c
index 0e1f415..58fb9d3 100644
--- a/hw/pl110.c
+++ b/hw/pl110.c
@@ -469,28 +469,49 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl110_init;
+}
+
+static DeviceInfo pl110_info = {
+    .name = "pl110",
+    .size = sizeof(pl110_state),
+    .vmsd = &vmstate_pl110,
+    .no_user = 1,
+    .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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl110_versatile_init;
+}
+
+static DeviceInfo pl110_versatile_info = {
+    .name = "pl110_versatile",
+    .size = sizeof(pl110_state),
+    .vmsd = &vmstate_pl110,
+    .no_user = 1,
+    .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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl111_init;
+}
+
+static DeviceInfo pl111_info = {
+    .name = "pl111",
+    .size = sizeof(pl110_state),
+    .vmsd = &vmstate_pl110,
+    .no_user = 1,
+    .class_init = pl111_class_init,
 };
 
 static void pl110_register_devices(void)
diff --git a/hw/pl181.c b/hw/pl181.c
index b79aa41..973d3fc 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -487,18 +487,25 @@ 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);
+
+    sdc->init = pl181_init;
+}
+
+static DeviceInfo pl181_info = {
+    .name = "pl181",
+    .size = sizeof(pl181_state),
+    .class_init = pl181_class_init,
+    .vmsd = &vmstate_pl181,
+    .reset = pl181_reset,
+    .no_user = 1,
 };
 
 static void pl181_register_devices(void)
 {
-    sysbus_register_withprop(&pl181_info);
+    sysbus_qdev_register(&pl181_info);
 }
 
 device_init(pl181_register_devices)
diff --git a/hw/pl190.c b/hw/pl190.c
index 6fc2656..79322aa 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -255,13 +255,20 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl190_init;
+}
+
+static DeviceInfo pl190_info = {
+    .name = "pl190",
+    .size = sizeof(pl190_state),
+    .vmsd = &vmstate_pl190,
+    .reset = pl190_reset,
+    .no_user = 1,
+    .class_init = pl190_class_init,
 };
 
 static void pl190_register_devices(void)
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index b38840e..36fb9f9 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -382,11 +382,18 @@ static DeviceInfo ppc4xx_host_bridge_info = {
     .class_init = ppc4xx_host_bridge_class_init,
 };
 
-static SysBusDeviceInfo ppc4xx_pcihost_info = {
-    .init         = ppc4xx_pcihost_initfn,
-    .qdev.name    = "ppc4xx-pcihost",
-    .qdev.size    = sizeof(PPC4xxPCIState),
-    .qdev.vmsd    = &vmstate_ppc4xx_pci,
+static void ppc4xx_pcihost_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = ppc4xx_pcihost_initfn;
+}
+
+static DeviceInfo ppc4xx_pcihost_info = {
+    .name    = "ppc4xx-pcihost",
+    .size    = sizeof(PPC4xxPCIState),
+    .vmsd    = &vmstate_ppc4xx_pci,
+    .class_init = ppc4xx_pcihost_class_init,
 };
 
 static void ppc4xx_pci_register(void)
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index bc783bf..f8c4f11 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -355,11 +355,18 @@ static DeviceInfo e500_host_bridge_info = {
     .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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = e500_pcihost_initfn;
+}
+
+static DeviceInfo e500_pcihost_info = {
+    .name = "e500-pcihost",
+    .size = sizeof(PPCE500PCIState),
+    .vmsd = &vmstate_ppce500_pci,
+    .class_init = e500_pcihost_class_init,
 };
 
 static void e500_pci_register(void)
diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c
index e7b1453..cb5bc97 100644
--- a/hw/ppce500_spin.c
+++ b/hw/ppce500_spin.c
@@ -203,10 +203,17 @@ 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 DeviceInfo ppce500_spin_info = {
+    .name = "e500-spin",
+    .size = sizeof(SpinState),
+    .class_init = ppce500_spin_class_init,
 };
 
 static void ppce500_spin_register(void)
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index 4ff1049..b3b85b7 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -154,12 +154,19 @@ static DeviceInfo raven_info = {
     .class_init = raven_class_init,
 };
 
-static SysBusDeviceInfo raven_pcihost_info = {
-    .qdev.name = "raven-pcihost",
-    .qdev.fw_name = "pci",
-    .qdev.size = sizeof(PREPPCIState),
-    .qdev.no_user = 1,
-    .init = raven_pcihost_init,
+static void raven_pcihost_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = raven_pcihost_init;
+}
+
+static DeviceInfo raven_pcihost_info = {
+    .name = "raven-pcihost",
+    .fw_name = "pci",
+    .size = sizeof(PREPPCIState),
+    .class_init = raven_pcihost_class_init,
+    .no_user = 1,
 };
 
 static void raven_register_devices(void)
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 2ebb739..fbc397f 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -1233,12 +1233,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_rtc_init;
+}
+
+static DeviceInfo pxa2xx_rtc_sysbus_info = {
+    .name = "pxa2xx_rtc",
+    .desc = "PXA2xx RTC Controller",
+    .size = sizeof(PXA2xxRTCState),
+    .vmsd = &vmstate_pxa2xx_rtc_regs,
+    .class_init = pxa2xx_rtc_sysbus_class_init,
 };
 
 /* I2C Interface */
@@ -1472,7 +1479,7 @@ static int pxa2xx_i2c_slave_init(I2CSlave *i2c)
     return 0;
 }
 
-static void pxapxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data)
+static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data)
 {
     I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
 
@@ -1485,7 +1492,7 @@ static void pxapxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data)
 static DeviceInfo pxa2xx_i2c_slave_info = {
     .name = "pxa2xx-i2c-slave",
     .size = sizeof(PXA2xxI2CSlaveState),
-    .class_init = pxapxa2xx_i2c_slave_class_init,
+    .class_init = pxa2xx_i2c_slave_class_init,
 };
 
 PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base,
@@ -1533,17 +1540,26 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_i2c_initfn;
+}
+
+static DeviceInfo pxa2xx_i2c_info = {
+    .name = "pxa2xx_i2c",
+    .desc = "PXA2xx I2C Bus Controller",
+    .size = sizeof(PXA2xxI2CState),
+    .vmsd = &vmstate_pxa2xx_i2c,
+    .props = pxa2xx_i2c_properties,
+    .class_init = pxa2xx_i2c_class_init,
 };
 
 /* PXA Inter-IC Sound Controller */
@@ -2295,10 +2311,23 @@ 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 DeviceInfo pxa2xx_ssp_info = {
+    .name = "pxa2xx-ssp",
+    .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_qdev_register(&pxa2xx_ssp_info);
     sysbus_register_withprop(&pxa2xx_i2c_info);
     sysbus_register_withprop(&pxa2xx_rtc_sysbus_info);
 }
diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c
index cb28107..9ecec33 100644
--- a/hw/pxa2xx_dma.c
+++ b/hw/pxa2xx_dma.c
@@ -543,16 +543,25 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_dma_init;
+}
+
+static DeviceInfo pxa2xx_dma_info = {
+    .name = "pxa2xx-dma",
+    .desc = "PXA2xx DMA controller",
+    .size = sizeof(PXA2xxDMAState),
+    .vmsd = &vmstate_pxa2xx_dma,
+    .props = pxa2xx_dma_properties,
+    .class_init = pxa2xx_dma_class_init,
 };
 
 static void pxa2xx_dma_register(void)
diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c
index cc58c40..7a1333f 100644
--- a/hw/pxa2xx_gpio.c
+++ b/hw/pxa2xx_gpio.c
@@ -317,16 +317,25 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_gpio_initfn;
+}
+
+static DeviceInfo pxa2xx_gpio_info = {
+    .name = "pxa2xx-gpio",
+    .desc = "PXA2xx GPIO controller",
+    .size = sizeof(PXA2xxGPIOInfo),
+    .props = pxa2xx_gpio_properties,
+    .class_init = pxa2xx_gpio_class_init,
 };
 
 static void pxa2xx_gpio_register(void)
diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c
index 92effbc..d318e83 100644
--- a/hw/pxa2xx_pic.c
+++ b/hw/pxa2xx_pic.c
@@ -296,12 +296,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_pic_initfn;
+}
+
+static DeviceInfo pxa2xx_pic_info = {
+    .name = "pxa2xx_pic",
+    .desc = "PXA2xx PIC",
+    .size = sizeof(PXA2xxPICState),
+    .vmsd = &vmstate_pxa2xx_pic_regs,
+    .class_init = pxa2xx_pic_class_init,
 };
 
 static void pxa2xx_pic_register(void)
diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c
index 50e2678..cd78d41 100644
--- a/hw/pxa2xx_timer.c
+++ b/hw/pxa2xx_timer.c
@@ -477,32 +477,50 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_timer_init;
+}
+
+static DeviceInfo pxa25x_timer_dev_info = {
+    .name = "pxa25x-timer",
+    .desc = "PXA25x timer",
+    .size = sizeof(PXA2xxTimerInfo),
+    .vmsd = &vmstate_pxa2xx_timer_regs,
+    .props = pxa25x_timer_dev_properties,
+    .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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_timer_init;
+}
+
+static DeviceInfo pxa27x_timer_dev_info = {
+    .name = "pxa27x-timer",
+    .desc = "PXA27x timer",
+    .size = sizeof(PXA2xxTimerInfo),
+    .vmsd = &vmstate_pxa2xx_timer_regs,
+    .props = pxa27x_timer_dev_properties,
+    .class_init = pxa27x_timer_dev_class_init,
 };
 
 static void pxa2xx_timer_register(void)
diff --git a/hw/realview.c b/hw/realview.c
index d2fde44..42a0f20 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -82,10 +82,17 @@ 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 DeviceInfo realview_i2c_info = {
+    .name = "realview_i2c",
+    .size = sizeof(RealViewI2CState),
+    .class_init = realview_i2c_class_init,
 };
 
 static void realview_register_devices(void)
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index 7342ede..0ccf21a 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -46,10 +46,22 @@ static int realview_gic_init(SysBusDevice *dev)
     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 DeviceInfo realview_gic_info = {
+    .name = "realview_gic",
+    .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);
+    sysbus_qdev_register(&realview_gic_info);
 }
 
 device_init(realview_gic_register_devices)
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index 2efea9f..8e34a78 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -419,11 +419,18 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = s390_virtio_bridge_init;
+}
+
+static DeviceInfo s390_virtio_bridge_info = {
+    .name = "s390-virtio-bridge",
+    .size = sizeof(SysBusDevice),
+    .no_user = 1,
+    .class_init = s390_virtio_bridge_class_init,
 };
 
 static void s390_virtio_register_devices(void)
diff --git a/hw/sbi.c b/hw/sbi.c
index 8965a71..0a062fc 100644
--- a/hw/sbi.c
+++ b/hw/sbi.c
@@ -131,12 +131,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sbi_init1;
+}
+
+static DeviceInfo sbi_info = {
+    .name = "sbi",
+    .size = sizeof(SBIState),
+    .vmsd = &vmstate_sbi,
+    .reset = sbi_reset,
+    .class_init = sbi_class_init,
 };
 
 static void sbi_register_devices(void)
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
index baeab9e..a849176 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;
@@ -162,10 +162,22 @@ static DeviceInfo sh_pci_host_info = {
     .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 DeviceInfo sh_pci_device_info = {
+    .name = "sh_pci",
+    .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);
+    sysbus_qdev_register(&sh_pci_device_info);
     pci_qdev_register(&sh_pci_host_info);
 }
 
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c
index 9925e64..12ce342 100644
--- a/hw/slavio_intctl.c
+++ b/hw/slavio_intctl.c
@@ -446,12 +446,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = slavio_intctl_init1;
+}
+
+static DeviceInfo slavio_intctl_info = {
+    .name = "slavio_intctl",
+    .size = sizeof(SLAVIO_INTCTLState),
+    .vmsd = &vmstate_intctl,
+    .reset = slavio_intctl_reset,
+    .class_init = slavio_intctl_class_init,
 };
 
 static void slavio_intctl_register_devices(void)
diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c
index 484301c..39a5269 100644
--- a/hw/slavio_misc.c
+++ b/hw/slavio_misc.c
@@ -468,18 +468,32 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = slavio_misc_init1;
+}
+
+static DeviceInfo slavio_misc_info = {
+    .name = "slavio_misc",
+    .size = sizeof(MiscState),
+    .vmsd = &vmstate_misc,
+    .reset = slavio_misc_reset,
+    .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 DeviceInfo apc_info = {
+    .name = "apc",
+    .size = sizeof(MiscState),
+    .class_init = apc_class_init,
 };
 
 static void slavio_misc_register_devices(void)
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
index 44b500a..a3bebcd 100644
--- a/hw/slavio_timer.c
+++ b/hw/slavio_timer.c
@@ -404,16 +404,25 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = slavio_timer_init1;
+}
+
+static DeviceInfo slavio_timer_info = {
+    .name = "slavio_timer",
+    .size = sizeof(SLAVIO_TIMERState),
+    .vmsd = &vmstate_slavio_timer,
+    .reset = slavio_timer_reset,
+    .props = slavio_timer_properties,
+    .class_init = slavio_timer_class_init,
 };
 
 static void slavio_timer_register_devices(void)
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index 4a68f6b..4220880 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -758,16 +758,25 @@ static int smc91c111_init1(SysBusDevice *dev)
     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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = smc91c111_init1;
+}
+
+static DeviceInfo smc91c111_info = {
+    .name = "smc91c111",
+    .size = sizeof(smc91c111_state),
+    .vmsd = &vmstate_smc91c111,
+    .reset = smc91c111_reset,
+    .props = smc91c111_properties,
+    .class_init = smc91c111_class_init,
 };
 
 static void smc91c111_register_devices(void)
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index 8a39f8f..b6ac0d4 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -227,10 +227,22 @@ static DeviceInfo spapr_main_pci_host_info = {
     .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 DeviceInfo spapr_phb_info = {
+    .name = "spapr-pci-host-bridge",
+    .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);
+    sysbus_qdev_register(&spapr_phb_info);
     pci_qdev_register(&spapr_main_pci_host_info);
 }
 
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index bc586bf..dc2e9c9 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -755,11 +755,18 @@ 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)
+{
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = spapr_vio_bridge_init;
+}
+
+static DeviceInfo spapr_vio_bridge_info = {
+    .name  = "spapr-vio-bridge",
+    .size  = sizeof(SysBusDevice),
+    .no_user = 1,
+    .class_init = spapr_vio_bridge_class_init,
 };
 
 static TypeInfo spapr_vio_type_info = {
diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
index 035d2e2..582f2f0 100644
--- a/hw/sparc32_dma.c
+++ b/hw/sparc32_dma.c
@@ -283,17 +283,26 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sparc32_dma_init1;
+}
+
+static DeviceInfo sparc32_dma_info = {
+    .name = "sparc32_dma",
+    .size = sizeof(DMAState),
+    .vmsd = &vmstate_dma,
+    .reset = dma_reset,
+    .props = sparc32_dma_properties,
+    .class_init = sparc32_dma_class_init,
 };
 
 static void sparc32_dma_register_devices(void)
diff --git a/hw/spitz.c b/hw/spitz.c
index a2a778f..046efad 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -1023,16 +1023,25 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sl_nand_init;
+}
+
+static DeviceInfo sl_nand_info = {
+    .name = "sl-nand",
+    .size = sizeof(SLNANDState),
+    .vmsd = &vmstate_sl_nand_info,
+    .props = sl_nand_properties,
+    .class_init = sl_nand_class_init,
 };
 
 static VMStateDescription vmstate_spitz_kbd = {
@@ -1049,14 +1058,23 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = spitz_keyboard_init;
+}
+
+static DeviceInfo spitz_keyboard_info = {
+    .name = "spitz-keyboard",
+    .size = sizeof(SpitzKeyboardState),
+    .vmsd = &vmstate_spitz_kbd,
+    .props = spitz_keyboard_properties,
+    .class_init = spitz_keyboard_class_init,
 };
 
 static const VMStateDescription vmstate_corgi_ssp_regs = {
@@ -1078,7 +1096,6 @@ static void corgi_ssp_class_init(ObjectClass *klass, void *data)
     k->transfer = corgi_ssp_transfer;
 }
 
-
 static DeviceInfo corgi_ssp_info = {
     .name = "corgi-ssp",
     .size = sizeof(CorgiSSPState),
diff --git a/hw/stellaris.c b/hw/stellaris.c
index a1620cb..b91139e 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -1408,14 +1408,50 @@ static DeviceInfo stellaris_ssi_bus_info = {
     .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 DeviceInfo stellaris_i2c_info = {
+    .name = "stellaris-i2c",
+    .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 DeviceInfo stellaris_gptm_info = {
+    .name = "stellaris-gptm",
+    .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 DeviceInfo stellaris_adc_info = {
+    .name = "stellaris-adc",
+    .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);
+    sysbus_qdev_register(&stellaris_i2c_info);
+    sysbus_qdev_register(&stellaris_gptm_info);
+    sysbus_qdev_register(&stellaris_adc_info);
     ssi_register_slave(&stellaris_ssi_bus_info);
 }
 
diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c
index ecd750c..3d3ef66 100644
--- a/hw/stellaris_enet.c
+++ b/hw/stellaris_enet.c
@@ -420,14 +420,23 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = stellaris_enet_init;
+}
+
+static DeviceInfo stellaris_enet_info = {
+    .name = "stellaris_enet",
+    .size = sizeof(stellaris_enet_state),
+    .props = stellaris_enet_properties,
+    .class_init = stellaris_enet_class_init,
 };
 
 static void stellaris_enet_register_devices(void)
diff --git a/hw/strongarm.c b/hw/strongarm.c
index fe63fd7..15828bf 100644
--- a/hw/strongarm.c
+++ b/hw/strongarm.c
@@ -201,12 +201,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = strongarm_pic_initfn;
+}
+
+static DeviceInfo strongarm_pic_info = {
+    .name = "strongarm_pic",
+    .desc = "StrongARM PIC",
+    .size = sizeof(StrongARMPICState),
+    .vmsd = &vmstate_strongarm_pic_regs,
+    .class_init = strongarm_pic_class_init,
 };
 
 /* Real-Time Clock */
@@ -413,12 +420,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = strongarm_rtc_init;
+}
+
+static DeviceInfo strongarm_rtc_sysbus_info = {
+    .name = "strongarm-rtc",
+    .desc = "StrongARM RTC Controller",
+    .size = sizeof(StrongARMRTCState),
+    .vmsd = &vmstate_strongarm_rtc_regs,
+    .class_init = strongarm_rtc_sysbus_class_init,
 };
 
 /* GPIO */
@@ -646,11 +660,18 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = strongarm_gpio_initfn;
+}
+
+static DeviceInfo strongarm_gpio_info = {
+    .name = "strongarm-gpio",
+    .desc = "StrongARM GPIO controller",
+    .size = sizeof(StrongARMGPIOInfo),
+    .class_init = strongarm_gpio_class_init,
 };
 
 /* Peripheral Pin Controller */
@@ -803,11 +824,18 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = strongarm_ppc_init;
+}
+
+static DeviceInfo strongarm_ppc_info = {
+    .name = "strongarm-ppc",
+    .desc = "StrongARM PPC controller",
+    .size = sizeof(StrongARMPPCInfo),
+    .class_init = strongarm_ppc_class_init,
 };
 
 /* UART Ports */
@@ -1245,17 +1273,26 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = strongarm_uart_init;
+}
+
+static DeviceInfo strongarm_uart_info = {
+    .name = "strongarm-uart",
+    .desc = "StrongARM UART controller",
+    .size = sizeof(StrongARMUARTState),
+    .reset = strongarm_uart_reset,
+    .vmsd = &vmstate_strongarm_uart_regs,
+    .props = strongarm_uart_properties,
+    .class_init = strongarm_uart_class_init,
 };
 
 /* Synchronous Serial Ports */
@@ -1479,13 +1516,20 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = strongarm_ssp_init;
+}
+
+static DeviceInfo strongarm_ssp_info = {
+    .name = "strongarm-ssp",
+    .desc = "StrongARM SSP controller",
+    .size = sizeof(StrongARMSSPState),
+    .reset = strongarm_ssp_reset,
+    .vmsd = &vmstate_strongarm_ssp_regs,
+    .class_init = strongarm_ssp_class_init,
 };
 
 /* Main CPU functions */
diff --git a/hw/sun4c_intctl.c b/hw/sun4c_intctl.c
index e15b167..111d31b 100644
--- a/hw/sun4c_intctl.c
+++ b/hw/sun4c_intctl.c
@@ -206,12 +206,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sun4c_intctl_init1;
+}
+
+static DeviceInfo sun4c_intctl_info = {
+    .name = "sun4c_intctl",
+    .size = sizeof(Sun4c_INTCTLState),
+    .vmsd = &vmstate_sun4c_intctl,
+    .reset = sun4c_intctl_reset,
+    .class_init = sun4c_intctl_class_init,
 };
 
 static void sun4c_intctl_register_devices(void)
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 941cc98..f2ff0bd 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -609,10 +609,17 @@ 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 DeviceInfo idreg_info = {
+    .name = "macio_idreg",
+    .size = sizeof(IDRegState),
+    .class_init = idreg_class_init,
 };
 
 static void idreg_register_devices(void)
@@ -650,10 +657,17 @@ 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 DeviceInfo afx_info = {
+    .name = "tcx_afx",
+    .size = sizeof(AFXState),
+    .class_init = afx_class_init,
 };
 
 static void afx_register_devices(void)
@@ -720,13 +734,22 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = prom_init1;
+}
+
+static DeviceInfo prom_info = {
+    .name = "openprom",
+    .size = sizeof(PROMState),
+    .props = prom_properties,
+    .class_init = prom_class_init,
 };
 
 static void prom_register_devices(void)
@@ -779,14 +802,23 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = ram_init1;
+}
+
+static DeviceInfo ram_info = {
+    .name = "memory",
+    .size = sizeof(RamDevice),
+    .props = ram_properties,
+    .class_init = ram_class_init,
 };
 
 static void ram_register_devices(void)
diff --git a/hw/sun4m_iommu.c b/hw/sun4m_iommu.c
index ef7627c..823bfac 100644
--- a/hw/sun4m_iommu.c
+++ b/hw/sun4m_iommu.c
@@ -357,16 +357,25 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = iommu_init1;
+}
+
+static DeviceInfo iommu_info = {
+    .name = "iommu",
+    .size = sizeof(IOMMUState),
+    .vmsd = &vmstate_iommu,
+    .reset = iommu_reset,
+    .props = iommu_properties,
+    .class_init = iommu_class_init,
 };
 
 static void iommu_register_devices(void)
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 6d9fdf6..f3bb226 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -643,13 +643,22 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = prom_init1;
+}
+
+static DeviceInfo prom_info = {
+    .name = "openprom",
+    .size = sizeof(PROMState),
+    .props = prom_properties,
+    .class_init = prom_class_init,
 };
 
 static void prom_register_devices(void)
@@ -695,14 +704,23 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = ram_init1;
+}
+
+static DeviceInfo ram_info = {
+    .name = "memory",
+    .size = sizeof(RamDevice),
+    .props = ram_properties,
+    .class_init = ram_class_init,
 };
 
 static void ram_register_devices(void)
diff --git a/hw/sysbus.c b/hw/sysbus.c
index 2e06fe8..7d122f9 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -107,29 +107,24 @@ void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size)
 
 static int sysbus_device_init(DeviceState *dev, DeviceInfo *base)
 {
-    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));
+    return sbc->init(sd);
 }
 
-void sysbus_register_withprop(SysBusDeviceInfo *info)
+void sysbus_qdev_register_subclass(DeviceInfo *info, const char *parent)
 {
-    info->qdev.init = sysbus_device_init;
-    info->qdev.bus_info = &system_bus_info;
+    info->init = sysbus_device_init;
+    info->bus_info = &system_bus_info;
 
-    assert(info->qdev.size >= sizeof(SysBusDevice));
-    qdev_register(&info->qdev);
+    assert(info->size >= sizeof(SysBusDevice));
+    qdev_register_subclass(info, parent);
 }
 
-void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init)
+void sysbus_qdev_register(DeviceInfo *info)
 {
-    SysBusDeviceInfo *info;
-
-    info = g_malloc0(sizeof(*info));
-    info->qdev.name = g_strdup(name);
-    info->qdev.size = size;
-    info->init = init;
-    sysbus_register_withprop(info);
+    sysbus_qdev_register_subclass(info, TYPE_SYS_BUS_DEVICE);
 }
 
 DeviceState *sysbus_create_varargs(const char *name,
@@ -258,3 +253,18 @@ MemoryRegion *sysbus_address_space(SysBusDevice *dev)
 {
     return get_system_memory();
 }
+
+static TypeInfo sysbus_device_type_info = {
+    .name = TYPE_SYS_BUS_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(SysBusDevice),
+    .abstract = true,
+    .class_size = sizeof(SysBusDeviceClass),
+};
+
+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 7b8ca23..a406077 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,14 @@ 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;
+#define sysbus_register_withprop(info) sysbus_qdev_register(info)
+void sysbus_qdev_register(DeviceInfo *info);
+void sysbus_qdev_register_subclass(DeviceInfo *info, const char *parent);
 
-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 b6a2753..7743c05 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -638,20 +638,29 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = tcx_init1;
+}
+
+static DeviceInfo tcx_info = {
+    .name = "SUNW,tcx",
+    .size = sizeof(TCXState),
+    .reset = tcx_reset,
+    .vmsd = &vmstate_tcx,
+    .props = tcx_properties,
+    .class_init = tcx_class_init,
 };
 
 static void tcx_register_devices(void)
diff --git a/hw/tusb6010.c b/hw/tusb6010.c
index 276300a..8e11c54 100644
--- a/hw/tusb6010.c
+++ b/hw/tusb6010.c
@@ -789,11 +789,18 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = tusb6010_init;
+}
+
+static DeviceInfo tusb6010_info = {
+    .name = "tusb6010",
+    .size = sizeof(TUSBState),
+    .reset = tusb6010_reset,
+    .class_init = tusb6010_class_init,
 };
 
 static void tusb6010_register_device(void)
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 6a148e0..2b394c0 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -407,43 +407,69 @@ static DeviceInfo unin_internal_pci_host_info = {
     .class_init = unin_internal_pci_host_class_init,
 };
 
-static SysBusDeviceInfo sysbus_unin_pci_host_info = {
-    .qdev.name = "uni-north-pci-pcihost",
-    .qdev.size = sizeof(UNINState),
-    .init      = pci_unin_main_init_device,
+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 DeviceInfo pci_unin_main_info = {
+    .name = "uni-north-pci-pchost",
+    .size = sizeof(UNINState),
+    .class_init = pci_unin_main_class_init,
 };
 
-static SysBusDeviceInfo sysbus_u3_agp_pci_host_info = {
-    .qdev.name = "u3-agp-pcihost",
-    .qdev.size = sizeof(UNINState),
-    .init      = pci_u3_agp_init_device,
+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 DeviceInfo pci_u3_agp_info = {
+    .name = "u3-agp-pcihost",
+    .size = sizeof(UNINState),
+    .class_init = pci_u3_agp_class_init,
 };
 
-static SysBusDeviceInfo sysbus_unin_agp_pci_host_info = {
-    .qdev.name = "uni-north-agp-pcihost",
-    .qdev.size = sizeof(UNINState),
-    .init      = pci_unin_agp_init_device,
+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 DeviceInfo pci_unin_agp_info = {
+    .name = "uni-north-agp-pcihost",
+    .size = sizeof(UNINState),
+    .class_init = pci_unin_agp_class_init,
 };
 
-static SysBusDeviceInfo sysbus_unin_internal_pci_host_info = {
-    .qdev.name = "uni-north-internal-pci-pcihost",
-    .qdev.size = sizeof(UNINState),
-    .init      = pci_unin_internal_init_device,
+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 DeviceInfo pci_unin_internal_info = {
+    .name = "uni-north-internal-pci-pichost",
+    .size = sizeof(UNINState),
+    .class_init = pci_unin_internal_class_init,
 };
 
 static void unin_register_devices(void)
 {
-    sysbus_register_withprop(&sysbus_unin_pci_host_info);
     pci_qdev_register(&unin_main_pci_host_info);
-
-    sysbus_register_withprop(&sysbus_u3_agp_pci_host_info);
     pci_qdev_register(&u3_agp_pci_host_info);
-
-    sysbus_register_withprop(&sysbus_unin_agp_pci_host_info);
     pci_qdev_register(&unin_agp_pci_host_info);
-
-    sysbus_register_withprop(&sysbus_unin_internal_pci_host_info);
     pci_qdev_register(&unin_internal_pci_host_info);
+
+    sysbus_register_withprop(&pci_unin_main_info);
+    sysbus_register_withprop(&pci_u3_agp_info);
+    sysbus_register_withprop(&pci_unin_agp_info);
+    sysbus_register_withprop(&pci_unin_internal_info);
 }
 
 device_init(unin_register_devices)
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index b9b37d5..3437da1 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1861,12 +1861,19 @@ static DeviceInfo ohci_pci_info = {
     .class_init = ohci_pci_class_init,
 };
 
-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[]) {
+static void ohci_sysbus_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = ohci_init_pxa;
+}
+
+static DeviceInfo ohci_sysbus_info = {
+    .name    = "sysbus-ohci",
+    .desc    = "OHCI USB Controller",
+    .size    = sizeof(OHCISysBusState),
+    .class_init = ohci_sysbus_class_init,
+    .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(),
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index 0eb7d32..c2eb4dd 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -125,11 +125,36 @@ static DeviceInfo versatile_pci_host_info = {
     .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 DeviceInfo pci_vpb_info = {
+    .name = "versatile_pci",
+    .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 DeviceInfo pci_realview_info = {
+    .name = "realview_pci",
+    .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);
+    sysbus_qdev_register(&pci_vpb_info);
+    sysbus_qdev_register(&pci_realview_info);
     pci_qdev_register(&versatile_pci_host_info);
 }
 
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 0312b75..3f7490c 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -365,12 +365,19 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = vpb_sic_init;
+}
+
+static DeviceInfo vpb_sic_info = {
+    .name = "versatilepb_sic",
+    .size = sizeof(vpb_sic_state),
+    .vmsd = &vmstate_vpb_sic,
+    .no_user = 1,
+    .class_init = vpb_sic_class_init,
 };
 
 static void versatilepb_register_devices(void)
diff --git a/hw/xgmac.c b/hw/xgmac.c
index ef0ca24..73840c9 100644
--- a/hw/xgmac.c
+++ b/hw/xgmac.c
@@ -403,12 +403,19 @@ static int xgmac_enet_init(SysBusDevice *dev)
     return 0;
 }
 
-static SysBusDeviceInfo xgmac_enet_info = {
-    .init = xgmac_enet_init,
-    .qdev.name  = "xgmac",
-    .qdev.size  = sizeof(struct XgmacState),
-    .qdev.vmsd = &vmstate_xgmac,
-    .qdev.props = (Property[]) {
+static void xgmac_enet_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = xgmac_enet_init;
+}
+
+static DeviceInfo xgmac_enet_info = {
+    .name  = "xgmac",
+    .size  = sizeof(struct XgmacState),
+    .vmsd = &vmstate_xgmac,
+    .class_init = xgmac_enet_class_init,
+    .props = (Property[]) {
         DEFINE_NIC_PROPERTIES(struct XgmacState, conf),
         DEFINE_PROP_END_OF_LIST(),
     }
diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c
index 0da20d9..0fbe415 100644
--- a/hw/xilinx_axidma.c
+++ b/hw/xilinx_axidma.c
@@ -486,15 +486,24 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_axidma_init;
+}
+
+static DeviceInfo axidma_info = {
+    .name = "xilinx,axidma",
+    .size = sizeof(struct XilinxAXIDMA),
+    .props = axidma_properties,
+    .class_init = axidma_class_init,
 };
 
 static void xilinx_axidma_register(void)
diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
index e713248..c7dbe00 100644
--- a/hw/xilinx_axienet.c
+++ b/hw/xilinx_axienet.c
@@ -870,18 +870,27 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_enet_init;
+}
+
+static DeviceInfo xilinx_enet_info = {
+    .name = "xilinx,axienet",
+    .size = sizeof(struct XilinxAXIEnet),
+    .props = xilinx_enet_properties,
+    .class_init = xilinx_enet_class_init,
 };
 static void xilinx_enet_register(void)
 {
diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c
index de595f4..dc7c0c8 100644
--- a/hw/xilinx_ethlite.c
+++ b/hw/xilinx_ethlite.c
@@ -226,16 +226,25 @@ static int xilinx_ethlite_init(SysBusDevice *dev)
     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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_ethlite_init;
+}
+
+static DeviceInfo xilinx_ethlite_info = {
+    .name = "xilinx,ethlite",
+    .size = sizeof(struct xlx_ethlite),
+    .props = xilinx_ethlite_properties,
+    .class_init = xilinx_ethlite_class_init,
 };
 
 static void xilinx_ethlite_register(void)
diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c
index c567885..c26b4ea 100644
--- a/hw/xilinx_intc.c
+++ b/hw/xilinx_intc.c
@@ -161,14 +161,23 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_intc_init;
+}
+
+static DeviceInfo xilinx_intc_info = {
+    .name = "xilinx,intc",
+    .size = sizeof(struct xlx_pic),
+    .props = xilinx_intc_properties,
+    .class_init = xilinx_intc_class_init,
 };
 
 static void xilinx_intc_register(void)
diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c
index adca53b..0755e1b 100644
--- a/hw/xilinx_timer.c
+++ b/hw/xilinx_timer.c
@@ -219,15 +219,24 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_timer_init;
+}
+
+static DeviceInfo xilinx_timer_info = {
+    .name = "xilinx,timer",
+    .size = sizeof(struct timerblock),
+    .props = xilinx_timer_properties,
+    .class_init = xilinx_timer_class_init,
 };
 
 static void xilinx_timer_register(void)
diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c
index 6533df9..8baabc7 100644
--- a/hw/xilinx_uartlite.c
+++ b/hw/xilinx_uartlite.c
@@ -211,10 +211,22 @@ static int xilinx_uartlite_init(SysBusDevice *dev)
     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 DeviceInfo xilinx_uartlite_info = {
+    .name = "xilinx,uartlite",
+    .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);
+    sysbus_qdev_register(&xilinx_uartlite_info);
 }
 
 device_init(xilinx_uart_register)
diff --git a/hw/zaurus.c b/hw/zaurus.c
index c4bcd29..b14240c 100644
--- a/hw/zaurus.c
+++ b/hw/zaurus.c
@@ -221,15 +221,24 @@ 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = scoop_init;
+}
+
+static DeviceInfo scoop_sysbus_info = {
+    .name = "scoop",
+    .desc = "Scoop2 Sharp custom ASIC",
+    .size = sizeof(ScoopInfo),
+    .vmsd = &vmstate_scoop_regs,
+    .props = scoop_sysbus_properties,
+    .class_init = scoop_sysbus_class_init,
 };
 
 static void scoop_register(void)
commit 40021f08882aaef93c66c8c740087b6d3031b63a
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Sun Dec 4 12:22:06 2011 -0600

    pci: convert to QEMU Object Model
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 1325f2f..aded048 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -163,23 +163,32 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo virtio_9p_info = {
+    .name = "virtio-9p-pci",
+    .size = sizeof(VirtIOPCIProxy),
+    .props = virtio_9p_properties,
+    .class_init = virtio_9p_class_init,
+    .reset = virtio_pci_reset,
 };
 
 static void virtio_9p_register_devices(void)
diff --git a/hw/ac97.c b/hw/ac97.c
index 03be99b..33b85f5 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -1344,21 +1344,30 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo ac97_info = {
+    .name = "AC97",
+    .desc = "Intel 82801AA AC97 Audio",
+    .size = sizeof (AC97LinkState),
+    .vmsd = &vmstate_ac97,
+    .props = ac97_properties,
+    .class_init = ac97_class_init,
 };
 
 static void ac97_register (void)
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 4d0b390..9058a7c 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_get_info(qdev), 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,23 +396,32 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo piix4_pm_info = {
+    .name = "PIIX4_PM",
+    .desc = "PM",
+    .size = sizeof(PIIX4PMState),
+    .vmsd = &vmstate_acpi,
+    .no_user = 1,
+    .props = piix4_pm_properties,
+    .class_init = piix4_pm_class_init,
 };
 
 static void piix4_pm_register(void)
@@ -485,14 +494,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_get_info(qdev), 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 +560,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/apb_pci.c b/hw/apb_pci.c
index 3a1b111..70cfc77 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -436,14 +436,21 @@ 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 DeviceInfo pbm_pci_host_info = {
+    .name = "pbm",
+    .size = sizeof(PCIDevice),
+    .class_init = pbm_pci_host_class_init,
 };
 
 static SysBusDeviceInfo pbm_host_info = {
@@ -453,18 +460,25 @@ static SysBusDeviceInfo pbm_host_info = {
     .init = pci_pbm_init_device,
 };
 
-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)
+{
+    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;
+}
+
+static DeviceInfo pbm_pci_bridge_info = {
+    .name = "pbm-bridge",
+    .size = sizeof(PCIBridge),
+    .vmsd = &vmstate_pci_device,
+    .reset = pci_bridge_reset,
+    .class_init = pbm_pci_bridge_class_init,
 };
 
 static void pbm_register_devices(void)
diff --git a/hw/bonito.c b/hw/bonito.c
index f2c7837..23384ec 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -766,18 +766,24 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo bonito_info = {
+    .name = "Bonito",
+    .desc = "Host bridge",
+    .size = sizeof(PCIBonitoState),
+    .vmsd = &vmstate_bonito,
+    .no_user = 1,
+    .class_init = bonito_class_init,
 };
 
 static SysBusDeviceInfo bonito_pcihost_info = {
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 1d36892..c203080 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2928,8 +2928,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, qdev_get_info(&dev->qdev));
-     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);
@@ -2963,17 +2963,24 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo cirrus_vga_info = {
+    .name = "cirrus-vga",
+    .desc = "Cirrus CLGD 54xx VGA",
+    .size = sizeof(PCICirrusVGAState),
+    .vmsd = &vmstate_pci_cirrus_vga,
+    .class_init = cirrus_vga_class_init,
 };
 
 static void cirrus_vga_register(void)
diff --git a/hw/dec_pci.c b/hw/dec_pci.c
index 08d4e06..7c3f50e 100644
--- a/hw/dec_pci.c
+++ b/hw/dec_pci.c
@@ -50,18 +50,25 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo dec_21154_pci_bridge_info = {
+    .name = "dec-21154-p2p-bridge",
+    .desc = "DEC 21154 PCI-PCI bridge",
+    .size = sizeof(PCIBridge),
+    .vmsd = &vmstate_pci_device,
+    .reset = pci_bridge_reset,
+    .class_init = dec_21154_pci_bridge_class_init,
 };
 
 PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
@@ -98,21 +105,29 @@ 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 DeviceInfo dec_21154_pci_host_info = {
+    .name = "dec-21154",
+    .size = sizeof(PCIDevice),
+    .class_init = dec_21154_pci_host_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);
 }
diff --git a/hw/e1000.c b/hw/e1000.c
index 7fc7318..200eed6 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -1197,23 +1197,32 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo e1000_info = {
+    .name = "e1000",
+    .desc = "Intel Gigabit Ethernet",
+    .size = sizeof(E1000State),
+    .reset = qdev_e1000_reset,
+    .vmsd = &vmstate_e1000,
+    .props = e1000_properties,
+    .class_init = e1000_class_init,
 };
 
 static void e1000_register_devices(void)
diff --git a/hw/eepro100.c b/hw/eepro100.c
index f0059c6..9f6d333 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -128,7 +128,13 @@
 #define DRVR_INT        0x0200  /* Driver generated interrupt. */
 
 typedef struct {
-    PCIDeviceInfo pci;
+    DeviceInfo qdev;
+
+    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,
-                                               qdev_get_info(&pci_dev->qdev));
+    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. */
@@ -1897,136 +1905,182 @@ static int e100_nic_init(PCIDevice *pci_dev)
 
 static E100PCIDeviceInfo e100_devices[] = {
     {
-        .pci.qdev.name = "i82550",
-        .pci.qdev.desc = "Intel i82550 Ethernet",
+        .qdev.name = "i82550",
+        .qdev.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",
+        .qdev.name = "i82551",
+        .qdev.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",
+        .qdev.name = "i82557a",
+        .qdev.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",
+        .qdev.name = "i82557b",
+        .qdev.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",
+        .qdev.name = "i82557c",
+        .qdev.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",
+        .qdev.name = "i82558a",
+        .qdev.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",
+        .qdev.name = "i82558b",
+        .qdev.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",
+        .qdev.name = "i82559a",
+        .qdev.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",
+        .qdev.name = "i82559b",
+        .qdev.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",
+        .qdev.name = "i82559c",
+        .qdev.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",
+        .qdev.name = "i82559er",
+        .qdev.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",
+        .qdev.name = "i82562",
+        .qdev.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",
+        .qdev.name = "i82801",
+        .qdev.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].qdev.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 void eepro100_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    E100PCIDeviceInfo *info;
+
+    info = eepro100_get_class_by_name(object_class_get_name(klass));
+
+    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 Property e100_properties[] = {
     DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
     DEFINE_PROP_END_OF_LIST(),
@@ -2036,17 +2090,13 @@ 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);
+        DeviceInfo *info = &e100_devices[i].qdev;
+
+        info->class_init = eepro100_class_init;
+        info->size = sizeof(EEPRO100State);
+        info->props = e100_properties;
+        
+        pci_qdev_register(info);
     }
 }
 
diff --git a/hw/es1370.c b/hw/es1370.c
index 3527eb6..205bed7 100644
--- a/hw/es1370.c
+++ b/hw/es1370.c
@@ -1031,18 +1031,25 @@ 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,
-    .subsystem_vendor_id = 0x4942,
-    .subsystem_id = 0x4c4c,
+static void es1370_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo es1370_info = {
+    .name = "ES1370",
+    .desc = "ENSONIQ AudioPCI ES1370",
+    .size = sizeof (ES1370State),
+    .vmsd = &vmstate_es1370,
+    .class_init = es1370_class_init,
 };
 
 static void es1370_register (void)
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index be10a6d..a790f97 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -121,15 +121,22 @@ static int grackle_pci_host_init(PCIDevice *d)
     return 0;
 }
 
-static PCIDeviceInfo grackle_pci_info = {
-    .qdev.name = "grackle",
-    .qdev.size = sizeof(PCIDevice),
-    .qdev.no_user = 1,
-    .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);
+
+    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;
+}
+
+static DeviceInfo grackle_pci_info = {
+    .name = "grackle",
+    .size = sizeof(PCIDevice),
+    .no_user = 1,
+    .class_init = grackle_pci_class_init,
 };
 
 static SysBusDeviceInfo grackle_pci_host_info = {
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index 432683a..9fc51f2 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -1136,14 +1136,21 @@ 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 DeviceInfo gt64120_pci_info = {
+    .name = "gt64120_pci",
+    .size = sizeof(PCIDevice),
+    .class_init = gt64120_pci_class_init,
 };
 
 static void gt64120_pci_register_devices(void)
diff --git a/hw/i82378.c b/hw/i82378.c
index 95ae274..99b453a 100644
--- a/hw/i82378.c
+++ b/hw/i82378.c
@@ -238,18 +238,25 @@ static int pci_i82378_init(PCIDevice *dev)
     return 0;
 }
 
-static PCIDeviceInfo pci_i82378_info = {
-    .init = pci_i82378_init,
-    .qdev.name = "i82378",
-    .qdev.size = sizeof(PCIi82378State),
-    .qdev.vmsd = &vmstate_pci_i82378,
-    .vendor_id = PCI_VENDOR_ID_INTEL,
-    .device_id = PCI_DEVICE_ID_INTEL_82378,
-    .revision = 0x03,
-    .class_id = PCI_CLASS_BRIDGE_ISA,
-    .subsystem_vendor_id = 0x0,
-    .subsystem_id = 0x0,
-    .qdev.props = (Property[]) {
+static void pci_i82378_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_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;
+}
+
+static DeviceInfo pci_i82378_info = {
+    .name = "i82378",
+    .size = sizeof(PCIi82378State),
+    .vmsd = &vmstate_pci_i82378,
+    .class_init = pci_i82378_class_init,
+    .props = (Property[]) {
         DEFINE_PROP_HEX32("iobase", PCIi82378State, isa_io_base, 0x80000000),
         DEFINE_PROP_HEX32("membase", PCIi82378State, isa_mem_base, 0xc0000000),
         DEFINE_PROP_END_OF_LIST()
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 99e7e6f..9c673bb 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -325,20 +325,28 @@ 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,
-    /* IDE controller revision */
-    .revision     = 0x07,
-    .class_id     = PCI_CLASS_STORAGE_IDE,
-    .qdev.props   = (Property[]) {
-        DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
-        DEFINE_PROP_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)
+{
+    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;
+}
+
+static DeviceInfo cmd646_ide_info = {
+    .name = "cmd646-ide",
+    .size = sizeof(PCIIDEState),
+    .props = cmd646_ide_properties,
+    .class_init = cmd646_ide_class_init,
 };
 
 static void cmd646_ide_register(void)
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index e6421e2..1cae9f1 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -146,18 +146,25 @@ 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,
+static void ich_ahci_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo ich_ahci_info = {
+    .name = "ich9-ahci",
+    .alias = "ahci",
+    .size = sizeof(AHCIPCIState),
+    .vmsd = &vmstate_ahci,
+    .class_init = ich_ahci_class_init,
 };
 
 static void ich_ahci_register(void)
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 91b77a2..832a507 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -237,39 +237,60 @@ PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
     return dev;
 }
 
-static PCIDeviceInfo piix3_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,
+static void piix3_ide_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo piix3_ide_info = {
+    .name = "piix3-ide",
+    .size = sizeof(PCIIDEState),
+    .no_user = 1,
+    .class_init = piix3_ide_class_init,
 };
 
-static PCIDeviceInfo piix3_ide_xen_info = {
-    .qdev.name    = "piix3-ide-xen",
-    .qdev.size    = sizeof(PCIIDEState),
-    .qdev.no_user = 1,
-    .qdev.unplug  = pci_piix3_xen_ide_unplug,
-    .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,
+static void piix3_ide_xen_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo piix3_ide_xen_info = {
+    .name = "piix3-ide-xen",
+    .size = sizeof(PCIIDEState),
+    .no_user = 1,
+    .class_init = piix3_ide_xen_class_init,
+    .unplug = pci_piix3_xen_ide_unplug,
 };
 
-static PCIDeviceInfo piix4_ide_info = {
-    .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,
+static void piix4_ide_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo piix4_ide_info = {
+    .name = "piix4-ide",
+    .size = sizeof(PCIIDEState),
+    .no_user = 1,
+    .class_init = piix4_ide_class_init,
 };
 
 static void piix_ide_register(void)
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 4ea2064..ef70864 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -213,16 +213,23 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo via_ide_info = {
+    .name = "via-ide",
+    .size = sizeof(PCIIDEState),
+    .no_user = 1,
+    .class_init = via_ide_class_init,
 };
 
 static void via_ide_register(void)
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index f727c22..f062133 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -79,7 +79,7 @@ void hda_codec_register(DeviceInfo *info)
     info->init = hda_codec_dev_init;
     info->exit = hda_codec_dev_exit;
     info->bus_info = &hda_codec_bus_info;
-    qdev_register(info);
+    qdev_register_subclass(info, TYPE_HDA_CODEC_DEVICE);
 }
 
 HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
@@ -1247,29 +1247,47 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo intel_hda_info = {
+    .name = "intel-hda",
+    .desc = "Intel HD Audio Controller",
+    .size = sizeof(IntelHDAState),
+    .vmsd = &vmstate_intel_hda,
+    .reset = intel_hda_reset,
+    .props = intel_hda_properties,
+    .class_init = intel_hda_class_init,
+};
+
+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),
 };
 
 static void intel_hda_register(void)
 {
     pci_qdev_register(&intel_hda_info);
+    type_register_static(&hda_codec_device_type_info);
 }
 device_init(intel_hda_register);
 
diff --git a/hw/ioh3420.c b/hw/ioh3420.c
index a6bfbb9..6cfafb3 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,31 +201,38 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo ioh3420_info = {
+    .name = "ioh3420",
+    .desc = "Intel IOH device id 3420 PCIE Root Port",
+    .size = sizeof(PCIESlot),
+    .reset = ioh3420_reset,
+    .vmsd = &vmstate_ioh3420,
+    .props = ioh3420_properties,
+    .class_init = ioh3420_class_init,
 };
 
 static void ioh3420_register(void)
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index bec2e0b..e2880be 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -766,25 +766,34 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo ivshmem_info = {
+    .name = "ivshmem",
+    .size = sizeof(IVShmemState),
+    .reset = ivshmem_reset,
+    .props = ivshmem_properties,
+    .class_init = ivshmem_class_init,
 };
 
 static void ivshmem_register_devices(void)
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 3a87171..3571588 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -2120,18 +2120,25 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo lsi_info = {
+    .name = "lsi53c895a",
+    .alias = "lsi",
+    .size = sizeof(LSIState),
+    .reset = lsi_scsi_reset,
+    .vmsd = &vmstate_lsi_scsi,
+    .class_init = lsi_class_init,
 };
 
 static void lsi53c895a_register_devices(void)
diff --git a/hw/macio.c b/hw/macio.c
index 357e0ea..ae9db08 100644
--- a/hw/macio.c
+++ b/hw/macio.c
@@ -81,12 +81,19 @@ static int macio_initfn(PCIDevice *d)
     return 0;
 }
 
-static PCIDeviceInfo macio_info = {
-    .qdev.name = "macio",
-    .qdev.size = sizeof(MacIOState),
-    .init = macio_initfn,
-    .vendor_id = PCI_VENDOR_ID_APPLE,
-    .class_id = PCI_CLASS_OTHERS << 8,
+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 DeviceInfo macio_info = {
+    .name = "macio",
+    .size = sizeof(MacIOState),
+    .class_init = macio_class_init,
 };
 
 static void macio_register(void)
diff --git a/hw/ne2000.c b/hw/ne2000.c
index b44eab1..138479a 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -786,19 +786,28 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo ne2000_info = {
+    .name = "ne2k_pci",
+    .size = sizeof(PCINE2000State),
+    .vmsd = &vmstate_pci_ne2000,
+    .props = ne2000_properties,
+    .class_init = ne2000_class_init,
 };
 
 static void ne2000_register_devices(void)
diff --git a/hw/pci.c b/hw/pci.c
index 516da08..6a0b1f5 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;
@@ -730,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);
@@ -756,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)) {
@@ -805,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;
@@ -840,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, qdev_get_info(dev));
+    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,28 +1456,27 @@ PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn)
 static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
     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, base->name, pci_dev->devfn);
     if (pci_dev == NULL)
         return -1;
-    if (qdev->hotplugged && info->no_hotplug) {
+    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;
@@ -1507,8 +1485,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);
@@ -1530,10 +1508,10 @@ 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_get_info(qdev), PCIDeviceInfo, qdev);
+    PCIDevice *dev = PCI_DEVICE(qdev);
+    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
 
-    if (info->no_hotplug) {
+    if (pc->no_hotplug) {
         qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev)));
         return -1;
     }
@@ -1541,23 +1519,15 @@ static int pci_unplug_device(DeviceState *qdev)
                              PCI_HOTPLUG_DISABLED);
 }
 
-void pci_qdev_register(PCIDeviceInfo *info)
-{
-    info->qdev.init = pci_qdev_init;
-    if (!info->qdev.unplug) {
-        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)
+void pci_qdev_register(DeviceInfo *info)
 {
-    while (info->qdev.name) {
-        pci_qdev_register(info);
-        info++;
+    info->init = pci_qdev_init;
+    if (!info->unplug) {
+        info->unplug = pci_unplug_device;
     }
+    info->exit = pci_unregister_device;
+    info->bus_info = &pci_bus_info;
+    qdev_register_subclass(info, TYPE_PCI_DEVICE);
 }
 
 PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
@@ -1568,7 +1538,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);
+    return PCI_DEVICE(dev);
 }
 
 PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
@@ -1985,7 +1955,7 @@ static int pci_qdev_find_recursive(PCIBus *bus,
     /* roughly check if given qdev is pci device */
     if (qdev_get_info(qdev)->init == &pci_qdev_init &&
         qdev->parent_bus->info == &pci_bus_info) {
-        *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
+        *pdev = PCI_DEVICE(qdev);
         return 0;
     }
     return -EINVAL;
@@ -2019,3 +1989,18 @@ MemoryRegion *pci_address_space_io(PCIDevice *dev)
 {
     return dev->bus->address_space_io;
 }
+
+static TypeInfo pci_device_type_info = {
+    .name = TYPE_PCI_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .abstract = true,
+    .class_size = sizeof(PCIDeviceClass),
+};
+
+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 5501d95..09b2324 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,40 +464,7 @@ 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);
+void pci_qdev_register(DeviceInfo *info);
 
 PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
                                     const char *name);
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index 650d165..1ed4339 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/pcie.c b/hw/pcie.c
index 5c9eb2f..7c92f19 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/pcnet-pci.c b/hw/pcnet-pci.c
index 4e164da..be3bd79 100644
--- a/hw/pcnet-pci.c
+++ b/hw/pcnet-pci.c
@@ -348,21 +348,30 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo pcnet_info = {
+    .name = "pcnet",
+    .size = sizeof(PCIPCNetState),
+    .reset = pci_reset,
+    .vmsd = &vmstate_pci_pcnet,
+    .props = pcnet_properties,
+    .class_init = pcnet_class_init,
 };
 
 static void pci_pcnet_register_devices(void)
diff --git a/hw/piix4.c b/hw/piix4.c
index 130dfd1..88be535 100644
--- a/hw/piix4.c
+++ b/hw/piix4.c
@@ -102,18 +102,24 @@ 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,
-    /* 82371AB/EB/MB PIIX4 PCI-to-ISA bridge */
-    .device_id    = PCI_DEVICE_ID_INTEL_82371AB_0,
-    .class_id     = PCI_CLASS_BRIDGE_ISA,
+static void piix4_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo piix4_info = {
+    .name = "PIIX4",
+    .desc = "ISA bridge",
+    .size = sizeof(PIIX4State),
+    .vmsd = &vmstate_piix4,
+    .no_user = 1,
+    .class_init = piix4_class_init,
 };
 
 static void piix4_register(void)
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 5cbeed5..787db4e 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -502,47 +502,68 @@ 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,
+static void piix3_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    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 DeviceInfo piix3_info = {
+    .name    = "PIIX3",
+    .desc    = "ISA bridge",
+    .size    = sizeof(PIIX3State),
+    .vmsd    = &vmstate_piix3,
+    .no_user = 1,
+    .class_init = piix3_class_init,
 };
 
-static PCIDeviceInfo piix3_info = {
-    .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,
+static void piix3_xen_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    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 PCIDeviceInfo piix3_xen_info = {
-    .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,
+static DeviceInfo piix3_xen_info = {
+    .name    = "PIIX3-xen",
+    .desc    = "ISA bridge",
+    .size    = sizeof(PIIX3State),
+    .vmsd    = &vmstate_piix3,
+    .no_user = 1,
+    .class_init = piix3_xen_class_init,
+};
+
+static void i440fx_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo i440fx_info = {
+    .name = "i440FX",
+    .desc = "Host bridge",
+    .size = sizeof(PCII440FXState),
+    .vmsd = &vmstate_i440fx,
+    .no_user = 1,
+    .class_init = i440fx_class_init,
 };
 
 static SysBusDeviceInfo i440fx_pcihost_info = {
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index 26de007..b38840e 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -366,13 +366,20 @@ static int ppc4xx_pcihost_initfn(SysBusDevice *dev)
     return 0;
 }
 
-static PCIDeviceInfo ppc4xx_host_bridge_info = {
-    .qdev.name    = "ppc4xx-host-bridge",
-    .qdev.desc    = "Host bridge",
-    .qdev.size    = sizeof(PCIDevice),
-    .vendor_id    = PCI_VENDOR_ID_IBM,
-    .device_id    = PCI_DEVICE_ID_IBM_440GX,
-    .class_id     = PCI_CLASS_BRIDGE_OTHER,
+static void ppc4xx_host_bridge_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->vendor_id    = PCI_VENDOR_ID_IBM;
+    k->device_id    = PCI_DEVICE_ID_IBM_440GX;
+    k->class_id     = PCI_CLASS_BRIDGE_OTHER;
+}
+
+static DeviceInfo ppc4xx_host_bridge_info = {
+    .name    = "ppc4xx-host-bridge",
+    .desc    = "Host bridge",
+    .size    = sizeof(PCIDevice),
+    .class_init = ppc4xx_host_bridge_class_init,
 };
 
 static SysBusDeviceInfo ppc4xx_pcihost_info = {
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index b606206..bc783bf 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -339,13 +339,20 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo e500_host_bridge_info = {
+    .name = "e500-host-bridge",
+    .desc = "Host bridge",
+    .size = sizeof(PCIDevice),
+    .class_init = e500_host_bridge_class_init,
 };
 
 static SysBusDeviceInfo e500_pcihost_info = {
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index 4961eed..4ff1049 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -134,21 +134,24 @@ static const VMStateDescription vmstate_raven = {
     },
 };
 
-static PCIDeviceInfo raven_info = {
-    .qdev.name = "raven",
-    .qdev.desc = "PReP Host Bridge - Motorola Raven",
-    .qdev.size = sizeof(RavenPCIState),
-    .qdev.vmsd = &vmstate_raven,
-    .qdev.no_user = 1,
-    .no_hotplug = 1,
-    .init = raven_init,
-    .vendor_id = PCI_VENDOR_ID_MOTOROLA,
-    .device_id = PCI_DEVICE_ID_MOTOROLA_RAVEN,
-    .revision = 0x00,
-    .class_id = PCI_CLASS_BRIDGE_HOST,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_END_OF_LIST()
-    },
+static void raven_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_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;
+}
+
+static DeviceInfo raven_info = {
+    .name = "raven",
+    .desc = "PReP Host Bridge - Motorola Raven",
+    .size = sizeof(RavenPCIState),
+    .vmsd = &vmstate_raven,
+    .no_user = 1,
+    .class_init = raven_class_init,
 };
 
 static SysBusDeviceInfo raven_pcihost_info = {
diff --git a/hw/qdev.c b/hw/qdev.c
index 81996bb..a8c24de 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -119,6 +119,7 @@ bool qdev_exists(const char *name)
 {
     return !!qdev_find_info(NULL, name);
 }
+
 static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
                                      Error **errp);
 
diff --git a/hw/qxl.c b/hw/qxl.c
index a00dc33..2f9470f 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1824,32 +1824,46 @@ static Property qxl_properties[] = {
         DEFINE_PROP_END_OF_LIST(),
 };
 
-static PCIDeviceInfo qxl_primary_info = {
-    .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)
+{
+    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;
+}
+
+static DeviceInfo qxl_primary_info = {
+    .name = "qxl-vga",
+    .desc = "Spice QXL GPU (primary, vga compatible)",
+    .size = sizeof(PCIQXLDevice),
+    .reset = qxl_reset_handler,
+    .vmsd = &qxl_vmstate,
+    .props = qxl_properties,
+    .class_init = qxl_primary_class_init,
 };
 
-static PCIDeviceInfo qxl_secondary_info = {
-    .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)
+{
+    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;
+}
+
+static DeviceInfo qxl_secondary_info = {
+    .name = "qxl",
+    .desc = "Spice QXL GPU (secondary)",
+    .size = sizeof(PCIQXLDevice),
+    .reset = qxl_reset_handler,
+    .vmsd = &qxl_vmstate,
+    .props = qxl_properties,
+    .class_init = qxl_secondary_class_init,
 };
 
 static void qxl_register(void)
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 2b55c7f..15dec9b 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -3494,22 +3494,31 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo rtl8139_info = {
+    .name = "rtl8139",
+    .size = sizeof(RTL8139State),
+    .reset = rtl8139_reset,
+    .vmsd = &vmstate_rtl8139,
+    .props = rtl8139_properties,
+    .class_init = rtl8139_class_init,
 };
 
 static void rtl8139_register_devices(void)
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
index d4d028d..baeab9e 100644
--- a/hw/sh_pci.c
+++ b/hw/sh_pci.c
@@ -147,12 +147,19 @@ 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 DeviceInfo sh_pci_host_info = {
+    .name = "sh_pci_host",
+    .size = sizeof(PCIDevice),
+    .class_init = sh_pci_host_class_init,
 };
 
 static void sh_pci_register_devices(void)
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index 2c95faa..8a39f8f 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -214,10 +214,17 @@ 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 DeviceInfo spapr_main_pci_host_info = {
+    .name = "spapr-pci-host-bridge",
+    .size = sizeof(PCIDevice),
+    .class_init = spapr_main_pci_host_class_init,
 };
 
 static void spapr_register_devices(void)
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 2dc3d04..6d9fdf6 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -562,14 +562,21 @@ 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 DeviceInfo ebus_info = {
+    .name = "ebus",
+    .size = sizeof(EbusState),
+    .class_init = ebus_class_init,
 };
 
 static void pci_ebus_register(void)
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 6a10013..6a148e0 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -339,44 +339,72 @@ static int unin_internal_pci_host_init(PCIDevice *d)
     return 0;
 }
 
-static PCIDeviceInfo unin_main_pci_host_info = {
-    .qdev.name = "uni-north-pci",
-    .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 DeviceInfo unin_main_pci_host_info = {
+    .name = "uni-north-pci",
+    .size = sizeof(PCIDevice),
+    .class_init = unin_main_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 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 DeviceInfo u3_agp_pci_host_info = {
+    .name = "u3-agp",
+    .size = sizeof(PCIDevice),
+    .class_init = u3_agp_pci_host_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 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 DeviceInfo unin_agp_pci_host_info = {
+    .name = "uni-north-agp",
+    .size = sizeof(PCIDevice),
+    .class_init = unin_agp_pci_host_class_init,
 };
 
-static PCIDeviceInfo unin_internal_pci_host_info = {
-    .qdev.name = "uni-north-internal-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 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 DeviceInfo unin_internal_pci_host_info = {
+    .name = "uni-north-internal-pci",
+    .size = sizeof(PCIDevice),
+    .class_init = unin_internal_pci_host_class_init,
 };
 
 static SysBusDeviceInfo sysbus_unin_pci_host_info = {
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 63fc3c7..8baff1d 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -2263,28 +2263,42 @@ 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,
+static void ehci_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo ehci_info = {
+    .name = "usb-ehci",
+    .size = sizeof(EHCIState),
+    .vmsd = &vmstate_ehci,
+    .props = ehci_properties,
+    .class_init = ehci_class_init,
 };
 
-static PCIDeviceInfo ich9_ehci_info = {
-    .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,
+static void ich9_ehci_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo ich9_ehci_info = {
+    .name = "ich9-usb-ehci1",
+    .size = sizeof(EHCIState),
+    .vmsd = &vmstate_ehci,
+    .props = ehci_properties,
+    .class_init = ich9_ehci_class_init,
 };
 
 static int usb_ehci_initfn(PCIDevice *dev)
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 2df6a6e..b9b37d5 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1836,20 +1836,29 @@ 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 void ohci_pci_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo ohci_pci_info = {
+    .name = "pci-ohci",
+    .desc = "Apple USB Controller",
+    .size = sizeof(OHCIPCIState),
+    .props = ohci_pci_properties,
+    .class_init = ohci_pci_class_init,
 };
 
 static SysBusDeviceInfo ohci_sysbus_info = {
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 1821063..e20d7c4 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -1192,79 +1192,121 @@ static Property uhci_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static PCIDeviceInfo piix3_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,
+static void piix3_uhci_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo piix3_uhci_info = {
+    .name = "piix3-usb-uhci",
+    .size = sizeof(UHCIState),
+    .vmsd = &vmstate_uhci,
+    .props = uhci_properties,
+    .class_init = piix3_uhci_class_init,
 };
 
-static PCIDeviceInfo piix4_uhci_info = {
-        .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,
+static void piix4_uhci_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo piix4_uhci_info = {
+    .name = "piix4-usb-uhci",
+    .size = sizeof(UHCIState),
+    .vmsd = &vmstate_uhci,
+    .props = uhci_properties,
+    .class_init = piix4_uhci_class_init,
 };
 
-static PCIDeviceInfo vt82c686b_uhci_info = {
-    .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,
+static void vt82c686b_uhci_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo vt82c686b_uhci_info = {
+    .name = "vt82c686b-usb-uhci",
+    .size = sizeof(UHCIState),
+    .vmsd = &vmstate_uhci,
+    .props = uhci_properties,
+    .class_init = vt82c686b_uhci_class_init,
 };
 
-static PCIDeviceInfo ich9_uhci1_info = {
-    .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,
+static void ich9_uhci1_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo ich9_uhci1_info = {
+    .name = "ich9-usb-uhci1",
+    .size = sizeof(UHCIState),
+    .vmsd = &vmstate_uhci,
+    .props = uhci_properties,
+    .class_init = ich9_uhci1_class_init,
 };
 
-static PCIDeviceInfo ich9_uhci2_info = {
-    .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,
+static void ich9_uhci2_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo ich9_uhci2_info = {
+    .name = "ich9-usb-uhci2",
+    .size = sizeof(UHCIState),
+    .vmsd = &vmstate_uhci,
+    .props = uhci_properties,
+    .class_init = ich9_uhci2_class_init,
 };
 
-static PCIDeviceInfo ich9_uhci3_info = {
-    .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,
+static void ich9_uhci3_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo ich9_uhci3_info = {
+    .name = "ich9-usb-uhci3",
+    .size = sizeof(UHCIState),
+    .vmsd = &vmstate_uhci,
+    .props = uhci_properties,
+    .class_init = ich9_uhci3_class_init,
 };
 
 static void uhci_register(void)
diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c
index 95bf010..fba2de3 100644
--- a/hw/usb-xhci.c
+++ b/hw/usb-xhci.c
@@ -2724,19 +2724,26 @@ static const VMStateDescription vmstate_xhci = {
     .unmigratable = 1,
 };
 
-static PCIDeviceInfo xhci_info = {
-    .qdev.name    = "nec-usb-xhci",
-    .qdev.alias   = "xhci",
-    .qdev.size    = sizeof(XHCIState),
-    .qdev.vmsd    = &vmstate_xhci,
-    .init         = usb_xhci_initfn,
-    .vendor_id    = PCI_VENDOR_ID_NEC,
-    .device_id    = PCI_DEVICE_ID_NEC_UPD720200,
-    .class_id     = PCI_CLASS_SERIAL_USB,
-    .revision     = 0x03,
-    .is_express   = 1,
-    .config_write = xhci_write_config,
-    .qdev.props   = (Property[]) {
+static void xhci_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    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 DeviceInfo xhci_info = {
+    .name    = "nec-usb-xhci",
+    .alias   = "xhci",
+    .size    = sizeof(XHCIState),
+    .vmsd    = &vmstate_xhci,
+    .class_init   = xhci_class_init,
+    .props   = (Property[]) {
         DEFINE_PROP_UINT32("msi", XHCIState, msi, 0),
         DEFINE_PROP_END_OF_LIST(),
     }
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index a285f7f..0eb7d32 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -109,14 +109,20 @@ 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 DeviceInfo versatile_pci_host_info = {
+    .name = "versatile_pci_host",
+    .size = sizeof(PCIDevice),
+    .class_init = versatile_pci_host_class_init,
 };
 
 static void versatile_pci_register_devices(void)
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index a75dbf3..ef9f8a5 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -75,18 +75,23 @@ 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)
+{
+    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;
+}
 
-    /* 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 DeviceInfo vga_info = {
+    .name = "VGA",
+    .size = sizeof(PCIVGAState),
+    .vmsd = &vmstate_vga_pci,
+    .class_init = vga_class_init,
 };
 
 static void vga_register(void)
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 72b53af..126fb08 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -806,88 +806,124 @@ static int virtio_balloon_exit_pci(PCIDevice *pci_dev)
     return virtio_exit_pci(pci_dev);
 }
 
-static PCIDeviceInfo virtio_blk_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,
+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 PCIDeviceInfo virtio_net_info = {
-    .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,
+static void virtio_blk_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo virtio_blk_info = {
+    .name = "virtio-blk-pci",
+    .alias = "virtio-blk",
+    .size = sizeof(VirtIOPCIProxy),
+    .props = virtio_blk_properties,
+    .reset = virtio_pci_reset,
+    .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)
+{
+    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;
+}
+
+static DeviceInfo virtio_net_info = {
+    .name = "virtio-net-pci",
+    .alias = "virtio-net",
+    .size = sizeof(VirtIOPCIProxy),
+    .props = virtio_net_properties,
+    .reset = virtio_pci_reset,
+    .class_init = virtio_net_class_init,
 };
 
-static PCIDeviceInfo virtio_serial_info = {
-    .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,
+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 PCIDeviceInfo virtio_balloon_info = {
-    .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,
+static void virtio_serial_class_init(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo virtio_serial_info = {
+    .name = "virtio-serial-pci",
+    .alias = "virtio-serial",
+    .size = sizeof(VirtIOPCIProxy),
+    .props = virtio_serial_properties,
+    .reset = virtio_pci_reset,
+    .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)
+{
+    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;
+}
+
+static DeviceInfo virtio_balloon_info = {
+    .name = "virtio-balloon-pci",
+    .alias = "virtio-balloon",
+    .size = sizeof(VirtIOPCIProxy),
+    .props = virtio_balloon_properties,
+    .reset = virtio_pci_reset,
+    .class_init = virtio_balloon_class_init,
 };
 
 static void virtio_pci_register_devices(void)
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index b1885c3..e7bbf7c 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1199,20 +1199,26 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo vmsvga_info = {
+    .name = "vmware-svga",
+    .size = sizeof(struct pci_vmsvga_state_s),
+    .vmsd = &vmstate_vmware_vga,
+    .reset = vmsvga_reset,
+    .class_init = vmsvga_class_init,
 };
 
 static void vmsvga_register(void)
diff --git a/hw/vt82c686.c b/hw/vt82c686.c
index 7fb88a5..72be4fd 100644
--- a/hw/vt82c686.c
+++ b/hw/vt82c686.c
@@ -346,15 +346,22 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo via_ac97_info = {
+    .name = "VT82C686B_AC97",
+    .desc = "AC97",
+    .size = sizeof(VT686AC97State),
+    .class_init = via_ac97_class_init,
 };
 
 static void vt82c686b_ac97_register(void)
@@ -385,15 +392,22 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo via_mc97_info = {
+    .name = "VT82C686B_MC97",
+    .desc = "MC97",
+    .size = sizeof(VT686MC97State),
+    .class_init = via_mc97_class_init,
 };
 
 static void vt82c686b_mc97_register(void)
@@ -451,21 +465,30 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo via_pm_info = {
+    .name = "VT82C686B_PM",
+    .desc = "PM",
+    .size = sizeof(VT686PMState),
+    .vmsd = &vmstate_acpi,
+    .props = via_pm_properties,
+    .class_init = via_pm_class_init,
 };
 
 static void vt82c686b_pm_register(void)
@@ -519,18 +542,25 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo via_info = {
+    .name = "VT82C686B",
+    .desc = "ISA bridge",
+    .size = sizeof(VT82C686BState),
+    .vmsd = &vmstate_via,
+    .no_user = 1,
+    .class_init = via_class_init,
 };
 
 static void vt82c686b_register(void)
diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
index 20d8673..a6ceff8 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,18 +425,25 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo i6300esb_info = {
+    .name = "i6300esb",
+    .size = sizeof(I6300State),
+    .vmsd = &vmstate_i6300esb,
+    .reset = i6300esb_reset,
+    .class_init = i6300esb_class_init,
 };
 
 static void i6300esb_register_devices(void)
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
index e62eaef..40687fb 100644
--- a/hw/xen_platform.c
+++ b/hw/xen_platform.c
@@ -372,20 +372,26 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo xen_platform_info = {
+    .name = "xen-platform",
+    .desc = "XEN platform pci device",
+    .size = sizeof(PCIXenPlatformState),
+    .vmsd = &vmstate_xen_platform,
+    .reset = platform_reset,
+    .class_init = xen_platform_class_init,
 };
 
 static void xen_platform_register(void)
diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c
index d3c387d..6d625cb 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,31 +167,38 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo xio3130_downstream_info = {
+    .name = "xio3130-downstream",
+    .desc = "TI X3130 Downstream Port of PCI Express Switch",
+    .size = sizeof(PCIESlot),
+    .reset = xio3130_downstream_reset,
+    .vmsd = &vmstate_xio3130_downstream,
+    .props = xio3130_downstream_properties,
+    .class_init = xio3130_downstream_class_init,
 };
 
 static void xio3130_downstream_register(void)
diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c
index 8283695..ec4c5e3 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,28 +144,35 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo xio3130_upstream_info = {
+    .name = "x3130-upstream",
+    .desc = "TI X3130 Upstream Port of PCI Express Switch",
+    .size = sizeof(PCIEPort),
+    .reset = xio3130_upstream_reset,
+    .vmsd = &vmstate_xio3130_upstream,
+    .props = xio3130_upstream_properties,
+    .class_init = xio3130_upstream_class_init,
 };
 
 static void xio3130_upstream_register(void)
commit 6e4ec3f9bb32d6f41e4fb30b872d2b7b084bc9a9
Author: Andreas Färber <afaerber at suse.de>
Date:   Thu Jan 19 07:40:18 2012 +0000

    unin_pci: Drop unused reset handler
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 8c03cb0..6a10013 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -63,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;
@@ -148,7 +144,6 @@ 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;
 }
 
@@ -169,8 +164,6 @@ 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;
 }
 
commit ff452aceafc7ba4aefb8dcf5542f5ba4f32b3e44
Author: Andreas Färber <afaerber at suse.de>
Date:   Thu Jan 19 07:40:17 2012 +0000

    unin_pci: Drop duplicate busdev
    
    PCIHostState already has a busdev.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index be0e98c..8c03cb0 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;
@@ -134,11 +133,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);
@@ -154,10 +155,12 @@ static int pci_unin_main_init_device(SysBusDevice *dev)
 
 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);
@@ -173,10 +176,12 @@ static int pci_u3_agp_init_device(SysBusDevice *dev)
 
 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 +194,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,6 +216,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
 {
     DeviceState *dev;
     SysBusDevice *s;
+    PCIHostState *h;
     UNINState *d;
 
     /* Use values found on a real PowerMac */
@@ -216,14 +224,15 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
     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,
@@ -272,6 +281,7 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic,
 {
     DeviceState *dev;
     SysBusDevice *s;
+    PCIHostState *h;
     UNINState *d;
 
     /* Uninorth AGP bus */
@@ -279,7 +289,8 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic,
     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,
@@ -287,7 +298,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,
commit 70f9c98744d92d89c9f67b5100edc7415b7316fc
Author: Andreas Färber <afaerber at suse.de>
Date:   Thu Jan 19 07:40:16 2012 +0000

    unin_pci: Clean up qdev names
    
    Add -pcihost to SysBus devices to resolve name conflicts,
    and clarify PCI vs. Internal PCI.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 14d9914..be0e98c 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -213,7 +213,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
 
     /* 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);
@@ -245,7 +245,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 +254,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);
@@ -275,7 +276,7 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic,
 
     /* 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);
@@ -335,7 +336,7 @@ static int unin_internal_pci_host_init(PCIDevice *d)
 }
 
 static PCIDeviceInfo unin_main_pci_host_info = {
-    .qdev.name = "uni-north",
+    .qdev.name = "uni-north-pci",
     .qdev.size = sizeof(PCIDevice),
     .init      = unin_main_pci_host_init,
     .vendor_id = PCI_VENDOR_ID_APPLE,
@@ -365,7 +366,7 @@ static PCIDeviceInfo unin_agp_pci_host_info = {
 };
 
 static PCIDeviceInfo unin_internal_pci_host_info = {
-    .qdev.name = "uni-north-pci",
+    .qdev.name = "uni-north-internal-pci",
     .qdev.size = sizeof(PCIDevice),
     .init      = unin_internal_pci_host_init,
     .vendor_id = PCI_VENDOR_ID_APPLE,
@@ -374,19 +375,42 @@ static PCIDeviceInfo unin_internal_pci_host_info = {
     .class_id  = PCI_CLASS_BRIDGE_HOST,
 };
 
+static SysBusDeviceInfo sysbus_unin_pci_host_info = {
+    .qdev.name = "uni-north-pci-pcihost",
+    .qdev.size = sizeof(UNINState),
+    .init      = pci_unin_main_init_device,
+};
+
+static SysBusDeviceInfo sysbus_u3_agp_pci_host_info = {
+    .qdev.name = "u3-agp-pcihost",
+    .qdev.size = sizeof(UNINState),
+    .init      = pci_u3_agp_init_device,
+};
+
+static SysBusDeviceInfo sysbus_unin_agp_pci_host_info = {
+    .qdev.name = "uni-north-agp-pcihost",
+    .qdev.size = sizeof(UNINState),
+    .init      = pci_unin_agp_init_device,
+};
+
+static SysBusDeviceInfo sysbus_unin_internal_pci_host_info = {
+    .qdev.name = "uni-north-internal-pci-pcihost",
+    .qdev.size = sizeof(UNINState),
+    .init      = pci_unin_internal_init_device,
+};
+
 static void unin_register_devices(void)
 {
-    sysbus_register_dev("uni-north", sizeof(UNINState),
-                        pci_unin_main_init_device);
+    sysbus_register_withprop(&sysbus_unin_pci_host_info);
     pci_qdev_register(&unin_main_pci_host_info);
-    sysbus_register_dev("u3-agp", sizeof(UNINState),
-                        pci_u3_agp_init_device);
+
+    sysbus_register_withprop(&sysbus_u3_agp_pci_host_info);
     pci_qdev_register(&u3_agp_pci_host_info);
-    sysbus_register_dev("uni-north-agp", sizeof(UNINState),
-                        pci_unin_agp_init_device);
+
+    sysbus_register_withprop(&sysbus_unin_agp_pci_host_info);
     pci_qdev_register(&unin_agp_pci_host_info);
-    sysbus_register_dev("uni-north-pci", sizeof(UNINState),
-                        pci_unin_internal_init_device);
+
+    sysbus_register_withprop(&sysbus_unin_internal_pci_host_info);
     pci_qdev_register(&unin_internal_pci_host_info);
 }
 
commit f82e35e38c0149dc201f1e329a215e6a6b739974
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Sun Dec 4 12:38:12 2011 -0600

    virtio-serial: convert to QEMU Object Model
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index f25adc4..73c3935 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,
-                                           qdev_get_info(&vcon->port.dev));
+    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,18 +124,27 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo virtconsole_info = {
+    .name = "virtconsole",
+    .size = sizeof(VirtConsole),
+    .props = virtconsole_properties,
+    .class_init = virtconsole_class_init,
 };
 
 static void virtconsole_register(void)
@@ -145,17 +153,26 @@ static void virtconsole_register(void)
 }
 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)
+{
+    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;
+}
+
+static DeviceInfo virtserialport_info = {
+    .name = "virtserialport",
+    .size = sizeof(VirtConsole),
+    .props = virtserialport_properties,
+    .class_init = virtserialport_class_init,
 };
 
 static void virtserialport_register(void)
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 982ffbf..70f5d48 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, qdev_get_info(&port->dev));
+    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, qdev_get_info(&port->dev));
+    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;
     }
@@ -751,7 +751,7 @@ static void remove_port(VirtIOSerial *vser, uint32_t port_id)
 static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
     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,
-                                           qdev_get_info(&port->dev));
+    VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
     VirtIOSerial *vser = port->vser;
 
     qemu_bh_delete(port->bh);
@@ -832,19 +831,19 @@ 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)
+void virtio_serial_port_qdev_register(DeviceInfo *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);
+    info->init = virtser_port_qdev_init;
+    info->bus_info = &virtser_bus_info;
+    info->exit = virtser_port_qdev_exit;
+    info->unplug = qdev_simple_unplug_cb;
+    qdev_register_subclass(info, TYPE_VIRTIO_SERIAL_PORT);
 }
 
 VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
@@ -940,3 +939,18 @@ void virtio_serial_exit(VirtIODevice *vdev)
 
     virtio_cleanup(vdev);
 }
+
+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),
+};
+
+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 ab13803..6207c89 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,48 +173,13 @@ 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);
+void virtio_serial_port_qdev_register(DeviceInfo *info);
 
 /*
  * Open a connection to the port
commit 3954d33ab7f82f5a5fa0ced231849920265a5fec
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Dec 15 16:31:06 2011 -0600

    spapr: convert to QEMU Object Model (v2)
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    ---
    v1 -> v2
     - use QOM to check for the default console

diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
index b9a5afc..0fb176a 100644
--- a/hw/spapr_llan.c
+++ b/hw/spapr_llan.c
@@ -474,20 +474,29 @@ static target_ulong h_multicast_ctrl(CPUState *env, sPAPREnvironment *spapr,
     return H_SUCCESS;
 }
 
-static VIOsPAPRDeviceInfo spapr_vlan_info = {
-    .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)
+{
+    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;
+}
+
+static DeviceInfo spapr_vlan_info = {
+    .name = "spapr-vlan",
+    .size = sizeof(VIOsPAPRVLANDevice),
+    .props = spapr_vlan_properties,
+    .class_init = spapr_vlan_class_init,
 };
 
 static void spapr_vlan_register(void)
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 0159413..bc586bf 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 *)qdev_get_info(&dev->qdev);
+    VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
     char *name;
 
     /* Device tree style name device at 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 *)qdev_get_info(&dev->qdev);
+    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;
         }
     }
@@ -649,12 +651,12 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev, VIOsPAPRDeviceInfo *info)
 
 static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
 {
-    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,16 @@ static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
 
     rtce_init(dev);
 
-    return info->init(dev);
+    return pc->init(dev);
 }
 
-void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info)
+void spapr_vio_bus_register_withprop(DeviceInfo *info)
 {
-    info->qdev.init = spapr_vio_busdev_init;
-    info->qdev.bus_info = &spapr_vio_bus_info;
+    info->init = spapr_vio_busdev_init;
+    info->bus_info = &spapr_vio_bus_info;
 
-    assert(info->qdev.size >= sizeof(VIOsPAPRDevice));
-    qdev_register(&info->qdev);
+    assert(info->size >= sizeof(VIOsPAPRDevice));
+    qdev_register_subclass(info, TYPE_VIO_SPAPR_DEVICE);
 }
 
 static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr,
@@ -694,15 +696,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 *)qdev_get_info(&dev->qdev);
+    pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
 
-    if (mode & ~info->signal_mask) {
+    if (mode & ~pc->signal_mask) {
         return H_PARAMETER;
     }
 
@@ -760,9 +762,18 @@ static SysBusDeviceInfo spapr_vio_bridge_info = {
     .qdev.no_user = 1,
 };
 
+static TypeInfo spapr_vio_type_info = {
+    .name = TYPE_VIO_SPAPR_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(VIOsPAPRDevice),
+    .abstract = true,
+    .class_size = sizeof(VIOsPAPRDeviceClass),
+};
+
 static void spapr_vio_register_devices(void)
 {
     sysbus_register_withprop(&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 0984d55..7d1155a 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,24 @@ 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 void spapr_vio_bus_register_withprop(DeviceInfo *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 21d946e..b83bb7f 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -947,19 +947,28 @@ static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
     return 0;
 }
 
-static VIOsPAPRDeviceInfo spapr_vscsi_info = {
-    .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)
+{
+    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;
+}
+
+static DeviceInfo spapr_vscsi_info = {
+    .name = "spapr-vscsi",
+    .size = sizeof(VSCSIState),
+    .props = spapr_vscsi_properties,
+    .class_init = spapr_vscsi_class_init,
 };
 
 static void spapr_vscsi_register(void)
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index 3d5c579..1780ffe 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -135,18 +135,27 @@ void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev)
     qdev_init_nofail(dev);
 }
 
-static VIOsPAPRDeviceInfo spapr_vty_info = {
-    .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)
+{
+    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+    k->init = spapr_vty_init;
+    k->dt_name = "vty";
+    k->dt_type = "serial";
+    k->dt_compatible = "hvterm1";
+}
+
+static DeviceInfo spapr_vty_info = {
+    .name = "spapr-vty",
+    .size = sizeof(VIOsPAPRVTYDevice),
+    .props = spapr_vty_properties,
+    .class_init = spapr_vty_class_init,
 };
 
 VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
@@ -163,7 +172,7 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
     selected = NULL;
     QTAILQ_FOREACH(iter, &bus->bus.children, sibling) {
         /* Only look at VTY devices */
-        if (qdev_get_info(iter) != &spapr_vty_info.qdev) {
+        if (!object_dynamic_cast(OBJECT(iter), "spapr-vty")) {
             continue;
         }
 
commit b9eea3e6a435a79fe308212157e0875442b760e4
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Dec 15 14:50:08 2011 -0600

    scsi: convert to QEMU Object Model
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 64e709e..d017ece 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)
 {
@@ -81,8 +117,7 @@ static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
 
 static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
-    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,24 +174,22 @@ 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)
+void scsi_qdev_register(DeviceInfo *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);
+    info->bus_info = &scsi_bus_info;
+    info->init     = scsi_qdev_init;
+    info->unplug   = qdev_simple_unplug_cb;
+    info->exit     = scsi_qdev_exit;
+    qdev_register_subclass(info, TYPE_SCSI_DEVICE);
 }
 
 /* handle legacy '-drive if=scsi,...' cmd line args */
@@ -182,7 +214,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 +310,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 +332,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 +430,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 +537,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 +627,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 +1395,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 +1410,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 +1421,18 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
     }
     return target_dev;
 }
+
+static TypeInfo scsi_device_type_info = {
+    .name = TYPE_SCSI_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(SCSIDevice),
+    .abstract = true,
+    .class_size = sizeof(SCSIDeviceClass),
+};
+
+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 11cfe73..2be6b67 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1712,75 +1712,108 @@ 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 void scsi_hd_class_initfn(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo scsi_hd_info = {
+    .name    = "scsi-hd",
+    .fw_name = "disk",
+    .desc    = "virtual SCSI disk",
+    .size    = sizeof(SCSIDiskState),
+    .reset   = scsi_disk_reset,
+    .class_init = scsi_hd_class_initfn,
+    .props   = (Property[]) {
+        DEFINE_SCSI_DISK_PROPERTIES(),
+        DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void scsi_cd_class_initfn(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo scsi_cd_info = {
+    .name    = "scsi-cd",
+    .fw_name = "disk",
+    .desc    = "virtual SCSI CD-ROM",
+    .size    = sizeof(SCSIDiskState),
+    .reset   = scsi_disk_reset,
+    .class_init = scsi_cd_class_initfn,
+    .props   = (Property[]) {
+        DEFINE_SCSI_DISK_PROPERTIES(),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
 #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 void scsi_block_class_initfn(ObjectClass *klass, void *data)
+{
+    SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+    sc->init         = scsi_block_initfn;
+    sc->destroy      = scsi_destroy;
+    sc->alloc_req    = scsi_block_new_request;
+}
+
+static DeviceInfo scsi_block_info = {
+    .name    = "scsi-block",
+    .fw_name = "disk",
+    .desc    = "SCSI block device passthrough",
+    .size    = sizeof(SCSIDiskState),
+    .reset   = scsi_disk_reset,
+    .class_init = scsi_block_class_initfn,
+    .props   = (Property[]) {
+        DEFINE_SCSI_DISK_PROPERTIES(),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
 #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 void scsi_disk_class_initfn(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo scsi_disk_info = {
+    .name    = "scsi-disk", /* legacy -device scsi-disk */
+    .fw_name = "disk",
+    .desc    = "virtual SCSI disk or CD-ROM (legacy)",
+    .size    = sizeof(SCSIDiskState),
+    .reset   = scsi_disk_reset,
+    .class_init = scsi_disk_class_initfn,
+    .props   = (Property[]) {
+        DEFINE_SCSI_DISK_PROPERTIES(),
+        DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
+        DEFINE_PROP_END_OF_LIST(),
     }
 };
 
 static void scsi_disk_register_devices(void)
 {
-    int i;
-
-    for (i = 0; i < ARRAY_SIZE(scsi_disk_info); i++) {
-        scsi_qdev_register(&scsi_disk_info[i]);
-    }
+    scsi_qdev_register(&scsi_hd_info);
+    scsi_qdev_register(&scsi_cd_info);
+#ifdef __linux__
+    scsi_qdev_register(&scsi_block_info);
+#endif
+    scsi_qdev_register(&scsi_disk_info);
 }
 device_init(scsi_disk_register_devices)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 0aebcdd..5cf4005 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,16 +457,23 @@ 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[]) {
+static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
+{
+    SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+    sc->init         = scsi_generic_initfn;
+    sc->destroy      = scsi_destroy;
+    sc->alloc_req    = scsi_new_request;
+}
+
+static DeviceInfo scsi_generic_info = {
+    .name    = "scsi-generic",
+    .fw_name = "disk",
+    .desc    = "pass through generic scsi device (/dev/sg*)",
+    .size    = sizeof(SCSIDevice),
+    .reset   = scsi_generic_reset,
+    .class_init = scsi_generic_class_initfn,
+    .props   = (Property[]) {
         DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
         DEFINE_PROP_END_OF_LIST(),
     },
diff --git a/hw/scsi.h b/hw/scsi.h
index ab6e952..4290b20 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,7 @@ struct SCSIBus {
 };
 
 void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info);
-void scsi_qdev_register(SCSIDeviceInfo *info);
+void scsi_qdev_register(DeviceInfo *info);
 
 static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
 {
commit d148211c6d64b6e59181a5b9c89117c541419cab
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 16 13:41:12 2011 -0600

    ide: convert to QEMU Object Model
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 00b28df..c808a0d 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/qdev.c b/hw/ide/qdev.c
index 4207127..b507e34 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -55,8 +55,8 @@ static char *idebus_get_fw_dev_path(DeviceState *dev)
 
 static int ide_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
-    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,17 +85,17 @@ 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)
+static void ide_qdev_register(DeviceInfo *info)
 {
-    info->qdev.init = ide_qdev_init;
-    info->qdev.bus_info = &ide_bus_info;
-    qdev_register(&info->qdev);
+    info->init = ide_qdev_init;
+    info->bus_info = &ide_bus_info;
+    qdev_register_subclass(info, TYPE_IDE_DEVICE);
 }
 
 IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive)
@@ -182,46 +182,73 @@ 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 void ide_hd_class_init(ObjectClass *klass, void *data)
+{
+    IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
+    k->init = ide_hd_initfn;
+}
+
+static DeviceInfo ide_hd_info = {
+    .name    = "ide-hd",
+    .fw_name = "drive",
+    .desc    = "virtual IDE disk",
+    .size    = sizeof(IDEDrive),
+    .class_init = ide_hd_class_init,
+    .props   = (Property[]) {
+        DEFINE_IDE_DEV_PROPERTIES(),
+        DEFINE_PROP_END_OF_LIST(),
     }
 };
 
-static void ide_dev_register(void)
+static void ide_cd_class_init(ObjectClass *klass, void *data)
 {
-    int i;
+    IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
+    k->init = ide_cd_initfn;
+}
 
-    for (i = 0; i < ARRAY_SIZE(ide_dev_info); i++) {
-        ide_qdev_register(&ide_dev_info[i]);
+static DeviceInfo ide_cd_info = {
+    .name    = "ide-cd",
+    .fw_name = "drive",
+    .desc    = "virtual IDE CD-ROM",
+    .size    = sizeof(IDEDrive),
+    .class_init = ide_cd_class_init,
+    .props   = (Property[]) {
+        DEFINE_IDE_DEV_PROPERTIES(),
+        DEFINE_PROP_END_OF_LIST(),
     }
+};
+
+static void ide_drive_class_init(ObjectClass *klass, void *data)
+{
+    IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
+    k->init = ide_drive_initfn;
+}
+
+static DeviceInfo ide_drive_info = {
+    .name    = "ide-drive", /* legacy -device ide-drive */
+    .fw_name = "drive",
+    .desc    = "virtual IDE disk or CD-ROM (legacy)",
+    .size    = sizeof(IDEDrive),
+    .class_init = ide_drive_class_init,
+    .props   = (Property[]) {
+        DEFINE_IDE_DEV_PROPERTIES(),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static TypeInfo ide_device_type_info = {
+    .name = TYPE_IDE_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(IDEDevice),
+    .abstract = true,
+    .class_size = sizeof(IDEDeviceClass),
+};
+
+static void ide_dev_register(void)
+{
+    ide_qdev_register(&ide_hd_info);
+    ide_qdev_register(&ide_cd_info);
+    ide_qdev_register(&ide_drive_info);
+    type_register_static(&ide_device_type_info);
 }
 device_init(ide_dev_register);
commit dbaa790451c1962f7e639f4d6f98be6efdea26ce
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 16 13:39:51 2011 -0600

    hda-codec: convert to QEMU Object Model
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/hda-audio.c b/hw/hda-audio.c
index 8053c74..2b3ce2f 100644
--- a/hw/hda-audio.c
+++ b/hw/hda-audio.c
@@ -906,33 +906,47 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo hda_audio_output_info = {
+    .name = "hda-output",
+    .desc = "HDA Audio Codec, output-only",
+    .size = sizeof(HDAAudioState),
+    .vmsd = &vmstate_hda_audio,
+    .props = hda_audio_properties,
+    .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)
+{
+    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;
+}
+
+static DeviceInfo hda_audio_duplex_info = {
+    .name = "hda-duplex",
+    .desc = "HDA Audio Codec, duplex",
+    .size = sizeof(HDAAudioState),
+    .vmsd = &vmstate_hda_audio,
+    .props = hda_audio_properties,
+    .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);
+    hda_codec_register(&hda_audio_output_info);
+    hda_codec_register(&hda_audio_duplex_info);
 }
 device_init(hda_audio_register);
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 6e1c5de..f727c22 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -51,9 +51,8 @@ static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
 {
     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,25 +60,26 @@ 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)
+void hda_codec_register(DeviceInfo *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);
+    info->init = hda_codec_dev_init;
+    info->exit = hda_codec_dev_exit;
+    info->bus_info = &hda_codec_bus_info;
+    qdev_register(info);
 }
 
 HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
@@ -283,6 +283,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 +299,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 +493,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);
         }
     }
 }
diff --git a/hw/intel-hda.h b/hw/intel-hda.h
index 65fd2a8..f523587 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,25 @@ 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);
+void hda_codec_register(DeviceInfo *info);
 HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad);
 
 void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response);
commit b5ea932781954355a9880e2744722cd05cc496f9
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Sun Dec 4 20:39:20 2011 -0600

    i2c: smbus: convert to QEMU Object Model
    
    This converts two types because smbus is implemented as a subclass of i2c.  It's
    extremely difficult to convert these two independently.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/ds1338.c b/hw/ds1338.c
index 1c4ba9f..4e09efe 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -118,13 +118,20 @@ 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 DeviceInfo ds1338_info = {
+    .name = "ds1338",
+    .size = sizeof(DS1338State),
+    .class_init = ds1338_class_init,
 };
 
 static void ds1338_register_devices(void)
diff --git a/hw/i2c.c b/hw/i2c.c
index 9efe70c..9e5d3df 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -83,6 +83,7 @@ int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
 {
     DeviceState *qdev;
     I2CSlave *slave = NULL;
+    I2CSlaveClass *sc;
 
     QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
         I2CSlave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
@@ -92,24 +93,33 @@ int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
         }
     }
 
-    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)
 {
     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;
 }
@@ -117,31 +127,50 @@ void i2c_end_transfer(i2c_bus *bus)
 int i2c_send(i2c_bus *bus, uint8_t data)
 {
     I2CSlave *dev = bus->current_dev;
+    I2CSlaveClass *sc;
 
-    if (!dev)
+    if (!dev) {
         return -1;
+    }
 
-    return dev->info->send(dev, data);
+    sc = I2C_SLAVE_GET_CLASS(dev);
+    if (sc->send) {
+        return sc->send(dev, data);
+    }
+
+    return -1;
 }
 
 int i2c_recv(i2c_bus *bus)
 {
     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)
 {
     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)
@@ -169,20 +198,23 @@ const VMStateDescription vmstate_i2c_slave = {
 
 static int i2c_slave_qdev_init(DeviceState *dev, DeviceInfo *base)
 {
-    I2CSlaveInfo *info = container_of(base, I2CSlaveInfo, qdev);
     I2CSlave *s = I2C_SLAVE_FROM_QDEV(dev);
+    I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s);
 
-    s->info = info;
+    return sc->init(s);
+}
 
-    return info->init(s);
+void i2c_register_slave_subclass(DeviceInfo *info, const char *parent)
+{
+    assert(info->size >= sizeof(I2CSlave));
+    info->init = i2c_slave_qdev_init;
+    info->bus_info = &i2c_bus_info;
+    qdev_register_subclass(info, parent);
 }
 
-void i2c_register_slave(I2CSlaveInfo *info)
+void i2c_register_slave(DeviceInfo *info)
 {
-    assert(info->qdev.size >= sizeof(I2CSlave));
-    info->qdev.init = i2c_slave_qdev_init;
-    info->qdev.bus_info = &i2c_bus_info;
-    qdev_register(&info->qdev);
+    i2c_register_slave_subclass(info, TYPE_I2C_SLAVE);
 }
 
 DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr)
@@ -194,3 +226,18 @@ DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr)
     qdev_init_nofail(dev);
     return dev;
 }
+
+static TypeInfo i2c_slave_type_info = {
+    .name = TYPE_I2C_SLAVE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(I2CSlave),
+    .abstract = true,
+    .class_size = sizeof(I2CSlaveClass),
+};
+
+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 d45cdad..31fd59c 100644
--- a/hw/i2c.h
+++ b/hw/i2c.h
@@ -17,29 +17,34 @@ enum i2c_event {
 
 typedef struct I2CSlave I2CSlave;
 
-/* Master to slave.  */
-typedef int (*i2c_send_cb)(I2CSlave *s, uint8_t data);
-/* Slave to master.  */
-typedef int (*i2c_recv_cb)(I2CSlave *s);
-/* Notify the slave of a bus state change.  */
-typedef void (*i2c_event_cb)(I2CSlave *s, enum i2c_event event);
+#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 I2CSlaveClass
+{
+    DeviceClass parent_class;
+
+    /* Callbacks provided by the device.  */
+    int (*init)(I2CSlave *dev);
 
-typedef int (*i2c_slave_initfn)(I2CSlave *dev);
+    /* Master to slave.  */
+    int (*send)(I2CSlave *s, uint8_t data);
 
-typedef struct {
-    DeviceInfo qdev;
+    /* Slave to master.  */
+    int (*recv)(I2CSlave *s);
 
-    /* Callbacks provided by the device.  */
-    i2c_slave_initfn init;
-    i2c_event_cb event;
-    i2c_recv_cb recv;
-    i2c_send_cb send;
-} I2CSlaveInfo;
+    /* 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;
@@ -57,7 +62,8 @@ int i2c_recv(i2c_bus *bus);
 #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);
+void i2c_register_slave(DeviceInfo *type);
+void i2c_register_slave_subclass(DeviceInfo *info, const char *parent);
 
 DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr);
 
diff --git a/hw/lm832x.c b/hw/lm832x.c
index 9e53cb3..84f81fe 100644
--- a/hw/lm832x.c
+++ b/hw/lm832x.c
@@ -494,14 +494,21 @@ 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)
+{
+    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;
+}
+
+static DeviceInfo lm8323_info = {
+    .name = "lm8323",
+    .size = sizeof(LM823KbdState),
+    .vmsd = &vmstate_lm_kbd,
+    .class_init = lm8323_class_init,
 };
 
 static void lm832x_register_devices(void)
diff --git a/hw/max7310.c b/hw/max7310.c
index a955236..0cc3219 100644
--- a/hw/max7310.c
+++ b/hw/max7310.c
@@ -185,15 +185,22 @@ static int max7310_init(I2CSlave *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)
+{
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->init = max7310_init;
+    k->event = max7310_event;
+    k->recv = max7310_rx;
+    k->send = max7310_tx;
+}
+
+static DeviceInfo max7310_info = {
+    .name = "max7310",
+    .size = sizeof(MAX7310State),
+    .vmsd = &vmstate_max7310,
+    .reset = max7310_reset,
+    .class_init = max7310_class_init,
 };
 
 static void max7310_register_devices(void)
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 895fb3f..2ebb739 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -1472,13 +1472,20 @@ static int pxa2xx_i2c_slave_init(I2CSlave *i2c)
     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 pxapxa2xx_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 DeviceInfo pxa2xx_i2c_slave_info = {
+    .name = "pxa2xx-i2c-slave",
+    .size = sizeof(PXA2xxI2CSlaveState),
+    .class_init = pxapxa2xx_i2c_slave_class_init,
 };
 
 PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base,
diff --git a/hw/smbus.c b/hw/smbus.c
index 0cb3566..ed31a59 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(I2CSlave *s, enum i2c_event event)
 {
-    SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
+    SMBusDevice *dev = SMBUS_DEVICE(s);
 
     switch (event) {
     case I2C_START_SEND:
@@ -150,14 +151,14 @@ static void smbus_i2c_event(I2CSlave *s, enum i2c_event event)
 
 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(I2CSlave *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;
@@ -184,7 +185,7 @@ static int smbus_i2c_recv(I2CSlave *s)
 
 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:
@@ -200,20 +201,16 @@ static int smbus_i2c_send(I2CSlave *s, uint8_t data)
 
 static int smbus_device_init(I2CSlave *i2c)
 {
-    SMBusDeviceInfo *t = container_of(i2c->info, SMBusDeviceInfo, i2c);
-    SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, i2c);
+    SMBusDevice *dev = SMBUS_DEVICE(i2c);
+    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
 
-    return t->init(dev);
+    return sc->init(dev);
 }
 
-void smbus_register_device(SMBusDeviceInfo *info)
+void smbus_register_device(DeviceInfo *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);
+    assert(info->size >= sizeof(SMBusDevice));
+    i2c_register_slave_subclass(info, TYPE_SMBUS_DEVICE);
 }
 
 /* Master device commands.  */
@@ -316,3 +313,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 2f2d49e..90fadee 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.  */
-    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;
-};
+#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,20 @@ 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;
+};
+
+void smbus_register_device(DeviceInfo *info);
 
 /* Master device commands.  */
 void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read);
@@ -69,3 +81,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 5d080ab..401dff5 100644
--- a/hw/smbus_eeprom.c
+++ b/hw/smbus_eeprom.c
@@ -104,19 +104,26 @@ 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[]) {
+static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo smbus_eeprom_info = {
+    .name = "smbus-eeprom",
+    .size = sizeof(SMBusEEPROMDevice),
+    .class_init = smbus_eeprom_class_initfn,
+    .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 void smbus_eeprom_register_devices(void)
diff --git a/hw/ssd0303.c b/hw/ssd0303.c
index 6a9a8a7..acf027f 100644
--- a/hw/ssd0303.c
+++ b/hw/ssd0303.c
@@ -294,14 +294,21 @@ static int ssd0303_init(I2CSlave *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)
+{
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->init = ssd0303_init;
+    k->event = ssd0303_event;
+    k->recv = ssd0303_recv;
+    k->send = ssd0303_send;
+}
+
+static DeviceInfo ssd0303_info = {
+    .name = "ssd0303",
+    .size = sizeof(ssd0303_state),
+    .vmsd = &vmstate_ssd0303,
+    .class_init = ssd0303_class_init,
 };
 
 static void ssd0303_register_devices(void)
diff --git a/hw/tmp105.c b/hw/tmp105.c
index ed8a0f3..12fe60d 100644
--- a/hw/tmp105.c
+++ b/hw/tmp105.c
@@ -226,14 +226,21 @@ static int tmp105_init(I2CSlave *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)
+{
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->init = tmp105_init;
+    k->event = tmp105_event;
+    k->recv = tmp105_rx;
+    k->send = tmp105_tx;
+}
+
+static DeviceInfo tmp105_info = {
+    .name = "tmp105",
+    .size = sizeof(TMP105State),
+    .vmsd = &vmstate_tmp105,
+    .class_init = tmp105_class_init,
 };
 
 static void tmp105_register_devices(void)
diff --git a/hw/tosa.c b/hw/tosa.c
index 5f4968d..9f112b1 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -259,13 +259,20 @@ 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 DeviceInfo tosa_dac_info = {
+    .name = "tosa_dac",
+    .size = sizeof(TosaDACState),
+    .class_init = tosa_dac_class_init,
  };
 
 static void tosa_ssp_class_init(ObjectClass *klass, void *data)
diff --git a/hw/twl92230.c b/hw/twl92230.c
index ced705c..ba4f8aa 100644
--- a/hw/twl92230.c
+++ b/hw/twl92230.c
@@ -857,14 +857,21 @@ static int twl92230_init(I2CSlave *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)
+{
+    I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+
+    sc->init = twl92230_init;
+    sc->event = menelaus_event;
+    sc->recv = menelaus_rx;
+    sc->send = menelaus_tx;
+}
+
+static DeviceInfo twl92230_info = {
+    .name ="twl92230",
+    .size = sizeof(MenelausState),
+    .vmsd = &vmstate_menelaus,
+    .class_init = twl92230_class_init,
 };
 
 static void twl92230_register_devices(void)
diff --git a/hw/wm8750.c b/hw/wm8750.c
index 5526bc4..33bce0d 100644
--- a/hw/wm8750.c
+++ b/hw/wm8750.c
@@ -689,14 +689,21 @@ 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)
+{
+    I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+
+    sc->init = wm8750_init;
+    sc->event = wm8750_event;
+    sc->recv = wm8750_rx;
+    sc->send = wm8750_tx;
+}
+
+static DeviceInfo wm8750_info = {
+    .name = "wm8750",
+    .size = sizeof(WM8750State),
+    .vmsd = &vmstate_wm8750,
+    .class_init = wm8750_class_init,
 };
 
 static void wm8750_register_devices(void)
diff --git a/hw/z2.c b/hw/z2.c
index 2984a60..b12f974 100644
--- a/hw/z2.c
+++ b/hw/z2.c
@@ -273,14 +273,21 @@ 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)
+{
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->init = aer915_init;
+    k->event = aer915_event;
+    k->recv = aer915_recv;
+    k->send = aer915_send;
+}
+
+static DeviceInfo aer915_info = {
+    .name = "aer915",
+    .size = sizeof(AER915State),
+    .vmsd = &vmstate_aer915_state,
+    .class_init = aer915_class_init,
 };
 
 static void z2_init(ram_addr_t ram_size,
commit 9e07bdf816b186632cda9651ac29bba76d299c03
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Sun Dec 4 20:28:27 2011 -0600

    i2c: rename i2c_slave -> I2CSlave
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/ds1338.c b/hw/ds1338.c
index f754cb7..1c4ba9f 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,7 +113,7 @@ 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;
 }
diff --git a/hw/i2c.c b/hw/i2c.c
index 9bcf3e1..9efe70c 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,10 +82,10 @@ 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;
 
     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;
@@ -104,7 +104,7 @@ int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
 
 void i2c_end_transfer(i2c_bus *bus)
 {
-    i2c_slave *dev = bus->current_dev;
+    I2CSlave *dev = bus->current_dev;
 
     if (!dev)
         return;
@@ -116,7 +116,7 @@ void i2c_end_transfer(i2c_bus *bus)
 
 int i2c_send(i2c_bus *bus, uint8_t data)
 {
-    i2c_slave *dev = bus->current_dev;
+    I2CSlave *dev = bus->current_dev;
 
     if (!dev)
         return -1;
@@ -126,7 +126,7 @@ int i2c_send(i2c_bus *bus, uint8_t data)
 
 int i2c_recv(i2c_bus *bus)
 {
-    i2c_slave *dev = bus->current_dev;
+    I2CSlave *dev = bus->current_dev;
 
     if (!dev)
         return -1;
@@ -136,7 +136,7 @@ int i2c_recv(i2c_bus *bus)
 
 void i2c_nack(i2c_bus *bus)
 {
-    i2c_slave *dev = bus->current_dev;
+    I2CSlave *dev = bus->current_dev;
 
     if (!dev)
         return;
@@ -146,7 +146,7 @@ void i2c_nack(i2c_bus *bus)
 
 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,13 +156,13 @@ 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()
     }
 };
@@ -170,7 +170,7 @@ const VMStateDescription vmstate_i2c_slave = {
 static int i2c_slave_qdev_init(DeviceState *dev, DeviceInfo *base)
 {
     I2CSlaveInfo *info = container_of(base, I2CSlaveInfo, qdev);
-    i2c_slave *s = I2C_SLAVE_FROM_QDEV(dev);
+    I2CSlave *s = I2C_SLAVE_FROM_QDEV(dev);
 
     s->info = info;
 
@@ -179,7 +179,7 @@ static int i2c_slave_qdev_init(DeviceState *dev, DeviceInfo *base)
 
 void i2c_register_slave(I2CSlaveInfo *info)
 {
-    assert(info->qdev.size >= sizeof(i2c_slave));
+    assert(info->qdev.size >= sizeof(I2CSlave));
     info->qdev.init = i2c_slave_qdev_init;
     info->qdev.bus_info = &i2c_bus_info;
     qdev_register(&info->qdev);
diff --git a/hw/i2c.h b/hw/i2c.h
index a3383ff..d45cdad 100644
--- a/hw/i2c.h
+++ b/hw/i2c.h
@@ -15,14 +15,16 @@ enum i2c_event {
     I2C_NACK /* Masker NACKed a receive byte.  */
 };
 
+typedef struct I2CSlave I2CSlave;
+
 /* Master to slave.  */
-typedef int (*i2c_send_cb)(i2c_slave *s, uint8_t data);
+typedef int (*i2c_send_cb)(I2CSlave *s, uint8_t data);
 /* Slave to master.  */
-typedef int (*i2c_recv_cb)(i2c_slave *s);
+typedef int (*i2c_recv_cb)(I2CSlave *s);
 /* Notify the slave of a bus state change.  */
-typedef void (*i2c_event_cb)(i2c_slave *s, enum i2c_event event);
+typedef void (*i2c_event_cb)(I2CSlave *s, enum i2c_event event);
 
-typedef int (*i2c_slave_initfn)(i2c_slave *dev);
+typedef int (*i2c_slave_initfn)(I2CSlave *dev);
 
 typedef struct {
     DeviceInfo qdev;
@@ -34,7 +36,7 @@ typedef struct {
     i2c_send_cb send;
 } I2CSlaveInfo;
 
-struct i2c_slave
+struct I2CSlave
 {
     DeviceState qdev;
     I2CSlaveInfo *info;
@@ -44,7 +46,7 @@ struct i2c_slave
 };
 
 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,7 +54,7 @@ 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);
@@ -69,7 +71,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 +80,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/lm832x.c b/hw/lm832x.c
index 992ce49..9e53cb3 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);
 
diff --git a/hw/max7310.c b/hw/max7310.c
index c1bdb2e..a955236 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);
 
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 6ddd500..895fb3f 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -1243,7 +1243,7 @@ static SysBusDeviceInfo pxa2xx_rtc_sysbus_info = {
 
 /* I2C Interface */
 typedef struct {
-    i2c_slave i2c;
+    I2CSlave i2c;
     PXA2xxI2CState *host;
 } PXA2xxI2CSlaveState;
 
@@ -1279,7 +1279,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 +1303,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 +1318,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,7 +1466,7 @@ 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;
diff --git a/hw/smbus.c b/hw/smbus.c
index ff027c8..0cb3566 100644
--- a/hw/smbus.c
+++ b/hw/smbus.c
@@ -65,7 +65,7 @@ static void smbus_do_write(SMBusDevice *dev)
     }
 }
 
-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);
 
@@ -148,7 +148,7 @@ 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);
@@ -182,7 +182,7 @@ 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);
 
@@ -198,7 +198,7 @@ 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);
diff --git a/hw/smbus.h b/hw/smbus.h
index a398715..2f2d49e 100644
--- a/hw/smbus.h
+++ b/hw/smbus.h
@@ -26,7 +26,7 @@
 
 struct SMBusDevice {
     /* The SMBus protocol is implemented on top of I2C.  */
-    i2c_slave i2c;
+    I2CSlave i2c;
 
     /* Remaining fields for internal use only.  */
     int mode;
diff --git a/hw/spitz.c b/hw/spitz.c
index 0f63139..a2a778f 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
diff --git a/hw/ssd0303.c b/hw/ssd0303.c
index bcad7bf..6a9a8a7 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);
 
diff --git a/hw/tmp105.c b/hw/tmp105.c
index f7e6f2b..ed8a0f3 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);
 
diff --git a/hw/tosa.c b/hw/tosa.c
index ade4cf6..5f4968d 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;
diff --git a/hw/twl92230.c b/hw/twl92230.c
index a75448f..ced705c 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);
 
diff --git a/hw/wm8750.c b/hw/wm8750.c
index 9fbdf3d..5526bc4 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);
diff --git a/hw/z2.c b/hw/z2.c
index f895892..2984a60 100644
--- a/hw/z2.c
+++ b/hw/z2.c
@@ -190,12 +190,12 @@ static DeviceInfo zipit_lcd_info = {
 };
 
 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;
@@ -213,7 +213,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) {
@@ -232,7 +232,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);
@@ -255,7 +255,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;
commit cd6c4cf28b529aaee0367256d37f349e3b125818
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 16 13:36:39 2011 -0600

    ssi: convert to QEMU Object Model
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/ads7846.c b/hw/ads7846.c
index de3f7af..c1b894e 100644
--- a/hw/ads7846.c
+++ b/hw/ads7846.c
@@ -153,11 +153,18 @@ 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 DeviceInfo ads7846_info = {
+    .name = "ads7846",
+    .size = sizeof(ADS7846State),
+    .class_init = ads7846_class_init,
 };
 
 static void ads7846_register_devices(void)
diff --git a/hw/max111x.c b/hw/max111x.c
index fc79814..db17842 100644
--- a/hw/max111x.c
+++ b/hw/max111x.c
@@ -153,18 +153,32 @@ 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 DeviceInfo max1110_info = {
+    .name = "max1110",
+    .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 DeviceInfo max1111_info = {
+    .name = "max1111",
+    .size = sizeof(MAX111xState),
+    .class_init = max1111_class_init,
 };
 
 static void max111x_register_devices(void)
diff --git a/hw/spitz.c b/hw/spitz.c
index 9d129c2..0f63139 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -1070,12 +1070,20 @@ 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)
+{
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = corgi_ssp_init;
+    k->transfer = corgi_ssp_transfer;
+}
+
+
+static DeviceInfo corgi_ssp_info = {
+    .name = "corgi-ssp",
+    .size = sizeof(CorgiSSPState),
+    .vmsd = &vmstate_corgi_ssp_regs,
+    .class_init = corgi_ssp_class_init,
 };
 
 static const VMStateDescription vmstate_spitz_lcdtg_regs = {
@@ -1090,12 +1098,19 @@ 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)
+{
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = spitz_lcdtg_init;
+    k->transfer = spitz_lcdtg_transfer;
+}
+
+static DeviceInfo spitz_lcdtg_info = {
+    .name = "spitz-lcdtg",
+    .size = sizeof(SpitzLCDTG),
+    .vmsd = &vmstate_spitz_lcdtg_regs,
+    .class_init = spitz_lcdtg_class_init,
 };
 
 static void spitz_register_devices(void)
diff --git a/hw/ssd0323.c b/hw/ssd0323.c
index 1eb3823..8e2fac8 100644
--- a/hw/ssd0323.c
+++ b/hw/ssd0323.c
@@ -340,11 +340,18 @@ 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 DeviceInfo ssd0323_info = {
+    .name = "ssd0323",
+    .size = sizeof(ssd0323_state),
+    .class_init = ssd0323_class_init,
 };
 
 static void ssd03232_register_devices(void)
diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
index 2d89cfe..2738cf9 100644
--- a/hw/ssi-sd.c
+++ b/hw/ssi-sd.c
@@ -244,11 +244,18 @@ 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 DeviceInfo ssi_sd_info = {
+    .name = "ssi-sd",
+    .size = sizeof(ssi_sd_state),
+    .class_init = ssi_sd_class_init,
 };
 
 static void ssi_sd_register_devices(void)
diff --git a/hw/ssi.c b/hw/ssi.c
index b47953a..99a0616 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -23,8 +23,8 @@ static struct BusInfo ssi_bus_info = {
 
 static int ssi_slave_init(DeviceState *dev, DeviceInfo *base_info)
 {
-    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,16 +33,15 @@ 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)
+void ssi_register_slave(DeviceInfo *info)
 {
-    assert(info->qdev.size >= sizeof(SSISlave));
-    info->qdev.init = ssi_slave_init;
-    info->qdev.bus_info = &ssi_bus_info;
-    qdev_register(&info->qdev);
+    assert(info->size >= sizeof(SSISlave));
+    info->init = ssi_slave_init;
+    info->bus_info = &ssi_bus_info;
+    qdev_register(info);
 }
 
 DeviceState *ssi_create_slave(SSIBus *bus, const char *name)
@@ -64,10 +63,12 @@ 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);
 }
diff --git a/hw/ssi.h b/hw/ssi.h
index 24610a8..97aefa7 100644
--- a/hw/ssi.h
+++ b/hw/ssi.h
@@ -15,22 +15,30 @@
 
 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);
+void ssi_register_slave(DeviceInfo *info);
 
 DeviceState *ssi_create_slave(SSIBus *bus, const char *name);
 
diff --git a/hw/stellaris.c b/hw/stellaris.c
index 7a73074..a1620cb 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -1394,11 +1394,18 @@ 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 DeviceInfo stellaris_ssi_bus_info = {
+    .name = "evb6965-ssi",
+    .size = sizeof(stellaris_ssi_bus_state),
+    .class_init = stellaris_ssi_bus_class_init,
 };
 
 static void stellaris_register_devices(void)
diff --git a/hw/tosa.c b/hw/tosa.c
index 0caba79..ade4cf6 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -266,13 +266,20 @@ static I2CSlaveInfo tosa_dac_info = {
     .event = tosa_dac_event,
     .recv = tosa_dac_recv,
     .send = tosa_dac_send
-};
+ };
+
+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 SSISlaveInfo tosa_ssp_info = {
-    .qdev.name = "tosa-ssp",
-    .qdev.size = sizeof(SSISlave),
-    .init = tosa_ssp_init,
-    .transfer = tosa_ssp_tansfer
+static DeviceInfo tosa_ssp_info = {
+    .name = "tosa-ssp",
+    .size = sizeof(SSISlave),
+    .class_init = tosa_ssp_class_init,
 };
 
 static void tosa_register_devices(void)
diff --git a/hw/z2.c b/hw/z2.c
index 8d48488..f895892 100644
--- a/hw/z2.c
+++ b/hw/z2.c
@@ -174,12 +174,19 @@ 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)
+{
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = zipit_lcd_init;
+    k->transfer = zipit_lcd_transfer;
+}
+
+static DeviceInfo zipit_lcd_info = {
+    .name = "zipit-lcd",
+    .size = sizeof(ZipitLCD),
+    .vmsd = &vmstate_zipit_lcd_state,
+    .class_init = zipit_lcd_class_init,
 };
 
 typedef struct {
commit ba7c05205c4ba2fd08096b0083fc1e5decf3c342
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Sun Dec 4 12:34:10 2011 -0600

    ccid: convert to QEMU Object Model
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c
index 2d2ebce..6dabe7a 100644
--- a/hw/ccid-card-emulated.c
+++ b/hw/ccid-card-emulated.c
@@ -564,16 +564,23 @@ 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[]) {
+static void emulated_class_initfn(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo emulated_card_info = {
+    .name = EMULATED_DEV_NAME,
+    .desc = "emulated smartcard",
+    .size = sizeof(EmulatedState),
+    .unplug    = qdev_simple_unplug_cb,
+    .class_init = emulated_class_initfn,
+    .props     = (Property[]) {
         DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
         DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
         DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c
index 9f51c6c..f563d97 100644
--- a/hw/ccid-card-passthru.c
+++ b/hw/ccid-card-passthru.c
@@ -316,16 +316,23 @@ 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[]) {
+static void passthru_class_initfn(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static DeviceInfo passthru_card_info = {
+    .name = PASSTHRU_DEV_NAME,
+    .desc = "passthrough smartcard",
+    .size = sizeof(PassthruState),
+    .vmsd = &passthru_vmstate,
+    .class_init = passthru_class_initfn,
+    .props     = (Property[]) {
         DEFINE_PROP_CHR("chardev", PassthruState, cs),
         DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
         DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/ccid.h b/hw/ccid.h
index 9e3abe1..9e4979c 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,7 @@ 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);
+void ccid_card_qdev_register(DeviceInfo *card);
 
 /*
  * support guest visible insertion/removal of ccid devices based on actual
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index eb63dfc..aff81fa 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;
@@ -741,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);
 }
@@ -827,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");
     }
@@ -1113,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_get_info(qdev));
+    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)
 {
-    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;
@@ -1146,20 +1177,19 @@ 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)
+void ccid_card_qdev_register(DeviceInfo *info)
 {
-    card->qdev.bus_info = &ccid_bus_info;
-    card->qdev.init = ccid_card_init;
-    card->qdev.exit = ccid_card_exit;
-    qdev_register(&card->qdev);
+    info->bus_info = &ccid_bus_info;
+    info->init = ccid_card_init;
+    info->exit = ccid_card_exit;
+    qdev_register_subclass(info, TYPE_CCID_CARD);
 }
 
 static int ccid_initfn(USBDevice *dev)
@@ -1170,7 +1200,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;
@@ -1312,8 +1341,17 @@ static struct DeviceInfo ccid_info = {
     },
 };
 
+static TypeInfo ccid_card_type_info = {
+    .name = TYPE_CCID_CARD,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(CCIDCardState),
+    .abstract = true,
+    .class_size = sizeof(CCIDCardClass),
+};
+
 static void ccid_register_devices(void)
 {
+    type_register_static(&ccid_card_type_info);
     usb_qdev_register(&ccid_info, "ccid", NULL);
 }
 device_init(ccid_register_devices)
commit 62aed76583fe8bf8e6ba5955b2ecfa3619ea3540
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Dec 15 14:53:10 2011 -0600

    usb: convert to QEMU Object Model
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/usb-audio.c b/hw/usb-audio.c
index b22d578..561ae31 100644
--- a/hw/usb-audio.c
+++ b/hw/usb-audio.c
@@ -674,21 +674,27 @@ static const VMStateDescription vmstate_usb_audio = {
     .unmigratable = 1,
 };
 
-static struct USBDeviceInfo usb_audio_info = {
-    .product_desc   = "QEMU USB Audio Interface",
-    .usbdevice_name = "audio",
-    .qdev.name      = "usb-audio",
-    .qdev.size      = sizeof(USBAudioState),
-    .qdev.vmsd      = &vmstate_usb_audio,
-    .usb_desc       = &desc_audio,
-    .init           = usb_audio_initfn,
-    .handle_packet  = usb_generic_handle_packet,
-    .handle_reset   = usb_audio_handle_reset,
-    .handle_control = usb_audio_handle_control,
-    .handle_data    = usb_audio_handle_data,
-    .handle_destroy = usb_audio_handle_destroy,
-    .set_interface  = usb_audio_set_interface,
-    .qdev.props = (Property[]) {
+static void usb_audio_class_init(ObjectClass *klass, void *data)
+{
+    USBDeviceClass *k = USB_DEVICE_CLASS(klass);
+
+    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 struct DeviceInfo usb_audio_info = {
+    .name      = "usb-audio",
+    .size      = sizeof(USBAudioState),
+    .vmsd      = &vmstate_usb_audio,
+    .class_init = usb_audio_class_init,
+    .props = (Property[]) {
         DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0),
         DEFINE_PROP_UINT32("buffer", USBAudioState, buffer,
                            8 * USBAUDIO_PACKET_SIZE),
@@ -698,7 +704,7 @@ static struct USBDeviceInfo usb_audio_info = {
 
 static void usb_audio_register_devices(void)
 {
-    usb_qdev_register(&usb_audio_info);
+    usb_qdev_register(&usb_audio_info, "audio", NULL);
 }
 
 device_init(usb_audio_register_devices)
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index 0c1270b..bf8c470 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -527,22 +527,29 @@ 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)
+{
+    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;
+}
+
+static struct DeviceInfo bt_info = {
+    .name      = "usb-bt-dongle",
+    .size      = sizeof(struct USBBtState),
+    .vmsd      = &vmstate_usb_bt,
+    .class_init= usb_bt_class_initfn,
 };
 
 static void usb_bt_register_devices(void)
 {
-    usb_qdev_register(&bt_info);
+    usb_qdev_register(&bt_info, NULL, NULL);
 }
 device_init(usb_bt_register_devices)
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index 9b67f18..aeef908 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -65,14 +65,104 @@ USBBus *usb_bus_find(int busnr)
     return NULL;
 }
 
+static int usb_device_init(USBDevice *dev)
+{
+    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, DeviceInfo *base)
 {
-    USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
-    USBDeviceInfo *info = DO_UPCAST(USBDeviceInfo, qdev, base);
+    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);
@@ -80,7 +170,7 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
     if (rc != 0) {
         return rc;
     }
-    rc = dev->info->init(dev);
+    rc = usb_device_init(dev);
     if (rc != 0) {
         usb_release_port(dev);
         return rc;
@@ -97,34 +187,43 @@ 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_qdev_register(DeviceInfo *info,
+                       const char *usbdevice_name,
+                       USBDevice *(*usbdevice_init)(const char *params))
 {
-    while (info->qdev.name) {
-        usb_qdev_register(info);
-        info++;
+    info->bus_info = &usb_bus_info;
+    info->init     = usb_qdev_init;
+    info->unplug   = qdev_simple_unplug_cb;
+    info->exit     = usb_qdev_exit;
+    qdev_register_subclass(info, TYPE_USB_DEVICE);
+
+    if (usbdevice_name) {
+        LegacyUSBFactory *f = g_malloc0(sizeof(*f));
+        f->name = info->name;
+        f->usbdevice_name = usbdevice_name;
+        f->usbdevice_init = usbdevice_init;
+        legacy_usb_factory = g_slist_append(legacy_usb_factory, f);
     }
 }
 
@@ -144,7 +243,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)
@@ -365,7 +464,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",
@@ -377,13 +476,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;
@@ -434,8 +533,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;
@@ -452,17 +551,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);
@@ -470,12 +565,27 @@ 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 TypeInfo usb_device_type_info = {
+    .name = TYPE_USB_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(USBDevice),
+    .abstract = true,
+    .class_size = sizeof(USBDeviceClass),
+};
+
+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 3b7f95d..eb63dfc 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -1286,28 +1286,34 @@ 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[]) {
+static void ccid_class_initfn(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static struct DeviceInfo ccid_info = {
+    .name      = CCID_DEV_NAME,
+    .desc      = "CCID Rev 1.1 smartcard reader",
+    .size      = sizeof(USBCCIDState),
+    .class_init= ccid_class_initfn,
+    .vmsd      = &ccid_vmstate,
+    .props     = (Property[]) {
         DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
         DEFINE_PROP_END_OF_LIST(),
     },
-    .qdev.vmsd      = &ccid_vmstate,
 };
 
 static void ccid_register_devices(void)
 {
-    usb_qdev_register(&ccid_info);
+    usb_qdev_register(&ccid_info, "ccid", NULL);
 }
 device_init(ccid_register_devices)
diff --git a/hw/usb-desc.c b/hw/usb-desc.c
index b3eb97b..3c3ed6a 100644
--- a/hw/usb-desc.c
+++ b/hw/usb-desc.c
@@ -297,8 +297,8 @@ static int usb_desc_set_interface(USBDevice *dev, int index, int value)
     dev->ifaces[index] = iface;
     usb_desc_ep_init(dev);
 
-    if (dev->info->set_interface && old != value) {
-        dev->info->set_interface(dev, index, old, value);
+    if (old != value) {
+        usb_device_set_interface(dev, index, old, value);
     }
     return 0;
 }
@@ -338,7 +338,7 @@ static int usb_desc_set_config(USBDevice *dev, int value)
 
 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) {
@@ -355,7 +355,7 @@ static void usb_desc_setdefaults(USBDevice *dev)
 
 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;
@@ -371,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)) {
@@ -380,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);
@@ -436,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;
         }
@@ -455,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;
@@ -463,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) {
@@ -520,7 +520,7 @@ 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;
+    const USBDesc *desc = usb_device_get_usb_desc(dev);
     int ret = -1;
 
     assert(desc != NULL);
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 997f828..88fdd35 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -553,53 +553,73 @@ 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_tablet_class_initfn(ObjectClass *klass, void *data)
+{
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->init           = usb_tablet_initfn;
+    uc->product_desc   = "QEMU USB Tablet";
+    uc->usb_desc       = &desc_tablet;
+    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 struct DeviceInfo usb_tablet_info = {
+    .name      = "usb-tablet",
+    .size      = sizeof(USBHIDState),
+    .vmsd      = &vmstate_usb_ptr,
+    .class_init= usb_tablet_class_initfn,
+};
+
+static void usb_mouse_class_initfn(ObjectClass *klass, void *data)
+{
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->init           = usb_mouse_initfn;
+    uc->product_desc   = "QEMU USB Mouse";
+    uc->usb_desc       = &desc_mouse;
+    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 struct DeviceInfo usb_mouse_info = {
+    .name      = "usb-mouse",
+    .size      = sizeof(USBHIDState),
+    .vmsd      = &vmstate_usb_ptr,
+    .class_init= usb_mouse_class_initfn,
+};
+
+static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
+{
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->init           = usb_keyboard_initfn;
+    uc->product_desc   = "QEMU USB Keyboard";
+    uc->usb_desc       = &desc_keyboard;
+    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 struct DeviceInfo usb_keyboard_info = {
+    .name      = "usb-kbd",
+    .size      = sizeof(USBHIDState),
+    .vmsd      = &vmstate_usb_kbd,
+    .class_init= usb_keyboard_class_initfn,
 };
 
 static void usb_hid_register_devices(void)
 {
-    usb_qdev_register_many(hid_info);
+    usb_qdev_register(&usb_tablet_info, "tablet", NULL);
+    usb_qdev_register(&usb_mouse_info, "mouse", NULL);
+    usb_qdev_register(&usb_keyboard_info, "keyboard", NULL);
 }
 device_init(usb_hid_register_devices)
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 069611b..ee4e6a6 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -533,23 +533,30 @@ 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)
+{
+    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;
+}
+
+static struct DeviceInfo hub_info = {
+    .name      = "usb-hub",
+    .fw_name   = "hub",
+    .size      = sizeof(USBHubState),
+    .vmsd      = &vmstate_usb_hub,
+    .class_init= usb_hub_class_initfn,
 };
 
 static void usb_hub_register_devices(void)
 {
-    usb_qdev_register(&hub_info);
+    usb_qdev_register(&hub_info, NULL, NULL);
 }
 device_init(usb_hub_register_devices)
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 186831d..ceb01e0 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -636,23 +636,28 @@ 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[]) {
+static void usb_msd_class_initfn(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static struct DeviceInfo msd_info = {
+    .name      = "usb-storage",
+    .fw_name   = "storage",
+    .size      = sizeof(MSDState),
+    .vmsd      = &vmstate_usb_msd,
+    .class_init= usb_msd_class_initfn,
+    .props     = (Property[]) {
         DEFINE_BLOCK_PROPERTIES(MSDState, conf),
         DEFINE_PROP_STRING("serial", MSDState, serial),
         DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
@@ -662,6 +667,6 @@ static struct USBDeviceInfo msd_info = {
 
 static void usb_msd_register_devices(void)
 {
-    usb_qdev_register(&msd_info);
+    usb_qdev_register(&msd_info, "disk", usb_msd_init);
 }
 device_init(usb_msd_register_devices)
diff --git a/hw/usb-net.c b/hw/usb-net.c
index fd4106b..57b58ac 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1385,29 +1385,34 @@ 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[]) {
+static void usb_net_class_initfn(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static struct DeviceInfo net_info = {
+    .name      = "usb-net",
+    .fw_name   = "network",
+    .size      = sizeof(USBNetState),
+    .vmsd      = &vmstate_usb_net,
+    .class_init= usb_net_class_initfn,
+    .props     = (Property[]) {
         DEFINE_NIC_PROPERTIES(USBNetState, conf),
         DEFINE_PROP_END_OF_LIST(),
-    }
+    },
 };
 
 static void usb_net_register_devices(void)
 {
-    usb_qdev_register(&net_info);
+    usb_qdev_register(&net_info, "net", usb_net_init);
 }
 device_init(usb_net_register_devices)
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index e3c8238..de49607 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -570,41 +570,51 @@ 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[]) {
+static void usb_serial_class_initfn(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static struct DeviceInfo serial_info = {
+    .name      = "usb-serial",
+    .size      = sizeof(USBSerialState),
+    .vmsd      = &vmstate_usb_serial,
+    .class_init= usb_serial_class_initfn,
+    .props     = (Property[]) {
         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[]) {
+static void usb_braille_class_initfn(ObjectClass *klass, void *data)
+{
+    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;
+}
+
+static struct DeviceInfo braille_info = {
+    .name      = "usb-braille",
+    .size      = sizeof(USBSerialState),
+    .vmsd      = &vmstate_usb_serial,
+    .class_init= usb_braille_class_initfn,
+    .props     = (Property[]) {
         DEFINE_PROP_CHR("chardev", USBSerialState, cs),
         DEFINE_PROP_END_OF_LIST(),
     },
@@ -612,7 +622,7 @@ static struct USBDeviceInfo braille_info = {
 
 static void usb_serial_register_devices(void)
 {
-    usb_qdev_register(&serial_info);
-    usb_qdev_register(&braille_info);
+    usb_qdev_register(&serial_info, "serial", usb_serial_init);
+    usb_qdev_register(&braille_info, "braille", usb_braille_init);
 }
 device_init(usb_serial_register_devices)
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 61d5b18..9b20a31 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -349,24 +349,30 @@ 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 *class, void *data)
+{
+    USBDeviceClass *uc = USB_DEVICE_CLASS(class);
+
+    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;
+}
+
+static struct DeviceInfo wacom_info = {
+    .name      = "usb-wacom-tablet",
+    .desc      = "QEMU PenPartner Tablet",
+    .size      = sizeof(USBWacomState),
+    .vmsd      = &vmstate_usb_wacom,
+    .class_init= usb_wacom_class_init,
 };
 
 static void usb_wacom_register_devices(void)
 {
-    usb_qdev_register(&wacom_info);
+    usb_qdev_register(&wacom_info, "wacom-tablet", NULL);
 }
 device_init(usb_wacom_register_devices)
diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c
index 28fe9de..95bf010 100644
--- a/hw/usb-xhci.c
+++ b/hw/usb-xhci.c
@@ -1458,7 +1458,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
     if (!xfer->in_xfer) {
         xhci_xfer_data(xfer, xfer->data, wLength, 0, 1, 0);
     }
-    ret = dev->info->handle_control(dev, &xfer->packet,
+    ret = usb_device_handle_control(dev, &xfer->packet,
                                     (bmRequestType << 8) | bRequest,
                                     wValue, wIndex, wLength, xfer->data);
 
@@ -1767,7 +1767,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
         slot->devaddr = xhci->devaddr++;
         slot_ctx[3] = (SLOT_ADDRESSED << SLOT_STATE_SHIFT) | slot->devaddr;
         DPRINTF("xhci: device address is %d\n", slot->devaddr);
-        dev->info->handle_control(dev, NULL,
+        usb_device_handle_control(dev, NULL,
                                   DeviceOutRequest | USB_REQ_SET_ADDRESS,
                                   slot->devaddr, 0, 0, NULL);
     }
diff --git a/hw/usb.c b/hw/usb.c
index 860538a..c3ff5b7 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,7 +322,7 @@ 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 = usb_ep_get(dev, p->pid, p->devep);
@@ -357,7 +353,7 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
 void usb_cancel_packet(USBPacket * p)
 {
     assert(p->owner != NULL);
-    p->owner->dev->info->cancel_packet(p->owner->dev, p);
+    usb_device_cancel_packet(p->owner->dev, p);
     p->owner = NULL;
 }
 
diff --git a/hw/usb.h b/hw/usb.h
index 37f7d96..5b9badb 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -1,3 +1,6 @@
+#ifndef QEMU_USB_H
+#define QEMU_USB_H
+
 /*
  * QEMU USB API
  *
@@ -150,7 +153,6 @@ 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;
 
@@ -183,7 +185,6 @@ struct USBEndpoint {
 /* definition of a USB device */
 struct USBDevice {
     DeviceState qdev;
-    USBDeviceInfo *info;
     USBPort *port;
     char *port_path;
     void *opaque;
@@ -219,8 +220,17 @@ struct USBDevice {
     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);
 
     /*
@@ -274,11 +284,7 @@ struct USBDeviceInfo {
 
     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);
@@ -412,8 +418,9 @@ 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_qdev_register(DeviceInfo *info,
+                       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);
@@ -445,4 +452,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/usb-bsd.c b/usb-bsd.c
index 1187552..2c6afc8 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -397,21 +397,28 @@ fail:
     return ret;
 }
 
-static struct USBDeviceInfo usb_host_dev_info = {
-    .product_desc   = "USB Host Device",
-    .qdev.name      = "usb-host",
-    .qdev.size      = sizeof(USBHostDevice),
-    .init           = usb_host_initfn,
-    .handle_packet  = usb_generic_handle_packet,
-    .handle_reset   = usb_host_handle_reset,
-    .handle_control = usb_host_handle_control,
-    .handle_data    = usb_host_handle_data,
-    .handle_destroy = usb_host_handle_destroy,
+static void usb_host_class_initfn(ObjectClass *klass, void *data)
+{
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->product_desc   = "USB Host Device";
+    uc->init           = usb_host_initfn;
+    uc->handle_packet  = usb_generic_handle_packet;
+    uc->handle_reset   = usb_host_handle_reset;
+    uc->handle_control = usb_host_handle_control;
+    uc->handle_data    = usb_host_handle_data;
+    uc->handle_destroy = usb_host_handle_destroy;
+}
+
+static struct DeviceInfo usb_host_dev_info = {
+    .name      = "usb-host",
+    .size      = sizeof(USBHostDevice),
+    .class_init= usb_host_initfn,
 };
 
 static void usb_host_register_devices(void)
 {
-    usb_qdev_register(&usb_host_dev_info);
+    usb_qdev_register(&usb_host_dev_info, NULL, NULL);
 }
 device_init(usb_host_register_devices)
 
diff --git a/usb-linux.c b/usb-linux.c
index 56898dd..31810f6 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -1402,21 +1402,26 @@ static const VMStateDescription vmstate_usb_host = {
     .unmigratable = 1,
 };
 
-static struct USBDeviceInfo usb_host_dev_info = {
-    .product_desc   = "USB Host Device",
-    .qdev.name      = "usb-host",
-    .qdev.size      = sizeof(USBHostDevice),
-    .qdev.vmsd      = &vmstate_usb_host,
-    .init           = usb_host_initfn,
-    .handle_packet  = usb_generic_handle_packet,
-    .cancel_packet  = usb_host_async_cancel,
-    .handle_data    = usb_host_handle_data,
-    .handle_control = usb_host_handle_control,
-    .handle_reset   = usb_host_handle_reset,
-    .handle_destroy = usb_host_handle_destroy,
-    .usbdevice_name = "host",
-    .usbdevice_init = usb_host_device_open,
-    .qdev.props     = (Property[]) {
+static void usb_host_class_initfn(ObjectClass *klass, void *data)
+{
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->init           = usb_host_initfn;
+    uc->product_desc   = "USB Host Device";
+    uc->handle_packet  = usb_generic_handle_packet;
+    uc->cancel_packet  = usb_host_async_cancel;
+    uc->handle_data    = usb_host_handle_data;
+    uc->handle_control = usb_host_handle_control;
+    uc->handle_reset   = usb_host_handle_reset;
+    uc->handle_destroy = usb_host_handle_destroy;
+}
+
+static struct DeviceInfo usb_host_dev_info = {
+    .name      = "usb-host",
+    .size      = sizeof(USBHostDevice),
+    .vmsd      = &vmstate_usb_host,
+    .class_init= usb_host_class_initfn,
+    .props     = (Property[]) {
         DEFINE_PROP_UINT32("hostbus",  USBHostDevice, match.bus_num,    0),
         DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr,       0),
         DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
@@ -1429,7 +1434,7 @@ static struct USBDeviceInfo usb_host_dev_info = {
 
 static void usb_host_register_devices(void)
 {
-    usb_qdev_register(&usb_host_dev_info);
+    usb_qdev_register(&usb_host_dev_info, "host", usb_host_device_open);
 }
 device_init(usb_host_register_devices)
 
diff --git a/usb-redir.c b/usb-redir.c
index 79d29ec..8f4a29a 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -1315,18 +1315,25 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id,
     }
 }
 
-static struct USBDeviceInfo usbredir_dev_info = {
-    .product_desc   = "USB Redirection Device",
-    .qdev.name      = "usb-redir",
-    .qdev.size      = sizeof(USBRedirDevice),
-    .init           = usbredir_initfn,
-    .handle_destroy = usbredir_handle_destroy,
-    .handle_packet  = usb_generic_handle_packet,
-    .cancel_packet  = usbredir_cancel_packet,
-    .handle_reset   = usbredir_handle_reset,
-    .handle_data    = usbredir_handle_data,
-    .handle_control = usbredir_handle_control,
-    .qdev.props     = (Property[]) {
+static void usbredir_class_initfn(ObjectClass *klass, void *data)
+{
+    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+    uc->init           = usbredir_initfn;
+    uc->product_desc   = "USB Redirection Device";
+    uc->handle_destroy = usbredir_handle_destroy;
+    uc->handle_packet  = usb_generic_handle_packet;
+    uc->cancel_packet  = usbredir_cancel_packet;
+    uc->handle_reset   = usbredir_handle_reset;
+    uc->handle_data    = usbredir_handle_data;
+    uc->handle_control = usbredir_handle_control;
+}
+
+static struct DeviceInfo usbredir_dev_info = {
+    .name      = "usb-redir",
+    .size      = sizeof(USBRedirDevice),
+    .class_init= usbredir_class_initfn,
+    .props     = (Property[]) {
         DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
         DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
         DEFINE_PROP_END_OF_LIST(),
@@ -1335,6 +1342,6 @@ static struct USBDeviceInfo usbredir_dev_info = {
 
 static void usbredir_register_devices(void)
 {
-    usb_qdev_register(&usbredir_dev_info);
+    usb_qdev_register(&usbredir_dev_info, NULL, NULL);
 }
 device_init(usbredir_register_devices);
commit 8f04ee0882aec9fe91fb70f767edf5dacff59835
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Sun Dec 4 11:52:49 2011 -0600

    isa: pic: convert to QEMU Object Model
    
    This converts two devices at once because PIC subclasses ISA and converting
    subclasses independently is extremely hard.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/applesmc.c b/hw/applesmc.c
index c47b592..a6e88bc 100644
--- a/hw/applesmc.c
+++ b/hw/applesmc.c
@@ -220,12 +220,18 @@ 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[]) {
+static void qdev_applesmc_class_init(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = applesmc_isa_init;
+}
+
+static DeviceInfo applesmc_isa_info = {
+    .name  = "isa-applesmc",
+    .size  = sizeof(struct AppleSMCStatus),
+    .reset = qdev_applesmc_isa_reset,
+    .class_init = qdev_applesmc_class_init,
+    .props = (Property[]) {
         DEFINE_PROP_HEX32("iobase", struct AppleSMCStatus, iobase,
                           APPLESMC_DEFAULT_IOBASE),
         DEFINE_PROP_STRING("osk", struct AppleSMCStatus, osk),
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 5b22cc3..1d36892 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2898,11 +2898,18 @@ static int vga_initfn(ISADevice *dev)
     return 0;
 }
 
-static ISADeviceInfo isa_cirrus_vga_info = {
-    .qdev.name     = "isa-cirrus-vga",
-    .qdev.size     = sizeof(ISACirrusVGAState),
-    .qdev.vmsd     = &vmstate_cirrus_vga,
-    .init          = vga_initfn,
+static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *k = ISA_DEVICE_CLASS(klass);
+
+    k->init          = vga_initfn;
+}
+
+static DeviceInfo isa_cirrus_vga_info = {
+    .name     = "isa-cirrus-vga",
+    .size     = sizeof(ISACirrusVGAState),
+    .vmsd     = &vmstate_cirrus_vga,
+    .class_init = isa_cirrus_vga_class_init,
 };
 
 static void isa_cirrus_vga_register(void)
diff --git a/hw/cs4231a.c b/hw/cs4231a.c
index dc77a3a..811c76b 100644
--- a/hw/cs4231a.c
+++ b/hw/cs4231a.c
@@ -665,13 +665,19 @@ 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[]) {
+static void cs4231a_class_initfn(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = cs4231a_initfn;
+}
+
+static DeviceInfo cs4231a_info = {
+    .name     = "cs4231a",
+    .desc     = "Crystal Semiconductor CS4231A",
+    .size     = sizeof (CSState),
+    .vmsd     = &vmstate_cs4231a,
+    .class_init = cs4231a_class_initfn,
+    .props    = (Property[]) {
         DEFINE_PROP_HEX32  ("iobase",  CSState, port, 0x534),
         DEFINE_PROP_UINT32 ("irq",     CSState, irq,  9),
         DEFINE_PROP_UINT32 ("dma",     CSState, dma,  3),
diff --git a/hw/debugcon.c b/hw/debugcon.c
index c9ee6d9..f290122 100644
--- a/hw/debugcon.c
+++ b/hw/debugcon.c
@@ -87,11 +87,17 @@ 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[]) {
+static void debugcon_isa_class_initfn(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = debugcon_isa_initfn;
+}
+
+static DeviceInfo debugcon_isa_info = {
+    .name  = "isa-debugcon",
+    .size  = sizeof(ISADebugconState),
+    .class_init = debugcon_isa_class_initfn,
+    .props = (Property[]) {
         DEFINE_PROP_HEX32("iobase", ISADebugconState, iobase, 0xe9),
         DEFINE_PROP_CHR("chardev",  ISADebugconState, state.chr),
         DEFINE_PROP_HEX32("readback", ISADebugconState, state.readback, 0xe9),
diff --git a/hw/fdc.c b/hw/fdc.c
index 70aa5c7..f761221 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1959,15 +1959,21 @@ 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[]) {
+static void isabus_fdc_class_init1(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = isabus_fdc_init1;
+}
+
+static DeviceInfo isa_fdc_info = {
+    .class_init = isabus_fdc_class_init1,
+    .name  = "isa-fdc",
+    .fw_name  = "fdc",
+    .size  = sizeof(FDCtrlISABus),
+    .no_user = 1,
+    .vmsd  = &vmstate_isa_fdc,
+    .reset = fdctrl_external_reset_isa,
+    .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),
diff --git a/hw/gus.c b/hw/gus.c
index ab872d8..6603aab 100644
--- a/hw/gus.c
+++ b/hw/gus.c
@@ -299,13 +299,19 @@ 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[]) {
+static void gus_class_initfn(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = gus_initfn;
+}
+
+static DeviceInfo gus_info = {
+    .name     = "gus",
+    .desc     = "Gravis Ultrasound GF1",
+    .size     = sizeof (GUSState),
+    .vmsd     = &vmstate_gus,
+    .class_init          = gus_class_initfn,
+    .props    = (Property[]) {
         DEFINE_PROP_UINT32 ("freq",    GUSState, freq,        44100),
         DEFINE_PROP_HEX32  ("iobase",  GUSState, port,        0x240),
         DEFINE_PROP_UINT32 ("irq",     GUSState, emu.gusirq,  7),
diff --git a/hw/i82374.c b/hw/i82374.c
index 616d1fc..2814379 100644
--- a/hw/i82374.c
+++ b/hw/i82374.c
@@ -135,12 +135,19 @@ static int i82374_isa_init(ISADevice *dev)
     return 0;
 }
 
-static ISADeviceInfo i82374_isa_info = {
-    .qdev.name  = "i82374",
-    .qdev.size  = sizeof(ISAi82374State),
-    .qdev.vmsd  = &vmstate_isa_i82374,
-    .init       = i82374_isa_init,
-    .qdev.props = (Property[]) {
+static void i82374_class_init(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *k = ISA_DEVICE_CLASS(klass);
+    
+    k->init       = i82374_isa_init;
+}
+
+static DeviceInfo i82374_isa_info = {
+    .name  = "i82374",
+    .size  = sizeof(ISAi82374State),
+    .vmsd  = &vmstate_isa_i82374,
+    .class_init = i82374_class_init,
+    .props = (Property[]) {
         DEFINE_PROP_HEX32("iobase", ISAi82374State, iobase, 0x400),
         DEFINE_PROP_END_OF_LIST()
     },
diff --git a/hw/i8254.c b/hw/i8254.c
index cf9ed2f..add1fab 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -535,14 +535,20 @@ 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[]) {
+static void pit_class_initfn(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = pit_initfn;
+}
+
+static DeviceInfo pit_info = {
+    .name     = "isa-pit",
+    .size     = sizeof(PITState),
+    .vmsd     = &vmstate_pit,
+    .reset    = pit_reset,
+    .no_user  = 1,
+    .class_init          = pit_class_initfn,
+    .props = (Property[]) {
         DEFINE_PROP_UINT32("irq", PITState, irq,  -1),
         DEFINE_PROP_HEX32("iobase", PITState, iobase,  -1),
         DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/i8259.c b/hw/i8259.c
index 3005ce2..e083bb6 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -472,10 +472,17 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
     return irq_set;
 }
 
-static PICCommonInfo i8259_info = {
-    .isadev.qdev.name  = "isa-i8259",
-    .isadev.qdev.reset = pic_reset,
-    .init              = pic_init,
+static void i8259_class_init(ObjectClass *klass, void *data)
+{
+    PICCommonClass *k = PIC_COMMON_CLASS(klass);
+
+    k->init = pic_init;
+}
+
+static DeviceInfo i8259_info = {
+    .name  = "isa-i8259",
+    .reset = pic_reset,
+    .class_init = i8259_class_init,
 };
 
 static void pic_register(void)
diff --git a/hw/i8259_common.c b/hw/i8259_common.c
index 7536897..24b1076 100644
--- a/hw/i8259_common.c
+++ b/hw/i8259_common.c
@@ -48,8 +48,7 @@ void pic_reset_common(PICCommonState *s)
 static void pic_dispatch_pre_save(void *opaque)
 {
     PICCommonState *s = opaque;
-    PICCommonInfo *info =
-        DO_UPCAST(PICCommonInfo, isadev.qdev, qdev_get_info(&s->dev.qdev));
+    PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
 
     if (info->pre_save) {
         info->pre_save(s);
@@ -59,8 +58,7 @@ static void pic_dispatch_pre_save(void *opaque)
 static int pic_dispatch_post_load(void *opaque, int version_id)
 {
     PICCommonState *s = opaque;
-    PICCommonInfo *info =
-        DO_UPCAST(PICCommonInfo, isadev.qdev, qdev_get_info(&s->dev.qdev));
+    PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
 
     if (info->post_load) {
         info->post_load(s);
@@ -71,8 +69,7 @@ static int pic_dispatch_post_load(void *opaque, int version_id)
 static int pic_init_common(ISADevice *dev)
 {
     PICCommonState *s = DO_UPCAST(PICCommonState, dev, dev);
-    PICCommonInfo *info =
-        DO_UPCAST(PICCommonInfo, isadev.qdev, qdev_get_info(&dev->qdev));
+    PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
 
     info->init(s);
 
@@ -136,12 +133,34 @@ static Property pic_properties_common[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
-void pic_qdev_register(PICCommonInfo *info)
+void pic_qdev_register(DeviceInfo *info)
 {
-    info->isadev.init = pic_init_common;
-    info->isadev.qdev.size = sizeof(PICCommonState);
-    info->isadev.qdev.vmsd = &vmstate_pic_common;
-    info->isadev.qdev.no_user = 1;
-    info->isadev.qdev.props = pic_properties_common;
-    isa_qdev_register(&info->isadev);
+    info->size = sizeof(PICCommonState);
+    info->vmsd = &vmstate_pic_common;
+    info->no_user = 1;
+    info->props = pic_properties_common;
+    isa_qdev_register_subclass(info, TYPE_PIC_COMMON);
 }
+
+static void pic_common_class_init(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+
+    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
index 13deb14..e9d1732 100644
--- a/hw/i8259_internal.h
+++ b/hw/i8259_internal.h
@@ -31,6 +31,22 @@
 
 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 */
@@ -58,19 +74,10 @@ struct PICCommonState {
     MemoryRegion elcr_io;
 };
 
-typedef struct PICCommonInfo PICCommonInfo;
-
-struct PICCommonInfo {
-    ISADeviceInfo isadev;
-    void (*init)(PICCommonState *s);
-    void (*pre_save)(PICCommonState *s);
-    void (*post_load)(PICCommonState *s);
-};
-
 void pic_reset_common(PICCommonState *s);
 
 ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master);
 
-void pic_qdev_register(PICCommonInfo *info);
+void pic_qdev_register(DeviceInfo *info);
 
 #endif /* !QEMU_I8259_INTERNAL_H */
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 219f3a4..464473a 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -94,13 +94,19 @@ 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[]) {
+static void isa_ide_class_initfn(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = isa_ide_initfn;
+}
+
+static DeviceInfo isa_ide_info = {
+    .name  = "isa-ide",
+    .fw_name  = "ide",
+    .size  = sizeof(ISAIDEState),
+    .class_init       = isa_ide_class_initfn,
+    .reset = isa_ide_reset,
+    .props = (Property[]) {
         DEFINE_PROP_HEX32("iobase",  ISAIDEState, iobase,  0x1f0),
         DEFINE_PROP_HEX32("iobase2", ISAIDEState, iobase2, 0x3f6),
         DEFINE_PROP_UINT32("irq",    ISAIDEState, isairq,  14),
diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index 5af790b..6943194 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -112,20 +112,29 @@ void isa_register_portio_list(ISADevice *dev, uint16_t start,
 
 static int isa_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
-    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);
+    }
+
+    return 0;
+}
+
+void isa_qdev_register_subclass(DeviceInfo *info, const char *parent)
+{
+    info->init = isa_qdev_init;
+    info->bus_info = &isa_bus_info;
+    qdev_register_subclass(info, parent);
 }
 
-void isa_qdev_register(ISADeviceInfo *info)
+void isa_qdev_register(DeviceInfo *info)
 {
-    info->qdev.init = isa_qdev_init;
-    info->qdev.bus_info = &isa_bus_info;
-    qdev_register(&info->qdev);
+    isa_qdev_register_subclass(info, TYPE_ISA_DEVICE);
 }
 
 ISADevice *isa_create(ISABus *bus, const char *name)
@@ -137,7 +146,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 +158,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 +172,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, "",
@@ -188,9 +197,18 @@ static SysBusDeviceInfo isabus_bridge_info = {
     .qdev.no_user = 1,
 };
 
+static TypeInfo isa_device_type_info = {
+    .name = TYPE_ISA_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(ISADevice),
+    .abstract = true,
+    .class_size = sizeof(ISADeviceClass),
+};
+
 static void isabus_register_devices(void)
 {
     sysbus_register_withprop(&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 b11a0be..9f5d158 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,12 @@ 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);
+void isa_qdev_register(DeviceInfo *info);
+void isa_qdev_register_subclass(DeviceInfo *info, const char *parent);
 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/kvm/i8259.c b/hw/kvm/i8259.c
index 64bb5c2..b34901c 100644
--- a/hw/kvm/i8259.c
+++ b/hw/kvm/i8259.c
@@ -112,12 +112,19 @@ qemu_irq *kvm_i8259_init(ISABus *bus)
     return qemu_allocate_irqs(kvm_pic_set_irq, NULL, ISA_NUM_IRQS);
 }
 
-static PICCommonInfo kvm_i8259_info = {
-    .isadev.qdev.name  = "kvm-i8259",
-    .isadev.qdev.reset = kvm_pic_reset,
-    .init       = kvm_pic_init,
-    .pre_save   = kvm_pic_get,
-    .post_load  = kvm_pic_put,
+static void kvm_i8259_class_init(ObjectClass *klass, void *data)
+{
+    PICCommonClass *k = PIC_COMMON_CLASS(klass);
+
+    k->init       = kvm_pic_init;
+    k->pre_save   = kvm_pic_get;
+    k->post_load  = kvm_pic_put;
+}
+
+static DeviceInfo kvm_i8259_info = {
+    .name  = "kvm-i8259",
+    .reset = kvm_pic_reset,
+    .class_init = kvm_i8259_class_init,
 };
 
 static void kvm_pic_register(void)
diff --git a/hw/m48t59.c b/hw/m48t59.c
index c043996..5912cd6 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -720,13 +720,19 @@ 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[]) {
+static void m48t59_init_class_isa1(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = m48t59_init_isa1;
+}
+
+static DeviceInfo m48t59_isa_info = {
+    .class_init = m48t59_init_class_isa1,
+    .name = "m48t59_isa",
+    .size = sizeof(M48t59ISAState),
+    .reset = m48t59_reset_isa,
+    .no_user = 1,
+    .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),
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 657fa10..685eb89 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -629,7 +629,7 @@ static void visit_type_int32(Visitor *v, int *value, const char *name, Error **e
 static void rtc_get_date(DeviceState *dev, Visitor *v, void *opaque,
                          const char *name, Error **errp)
 {
-    ISADevice *isa = DO_UPCAST(ISADevice, qdev, dev);
+    ISADevice *isa = ISA_DEVICE(dev);
     RTCState *s = DO_UPCAST(RTCState, dev, isa);
 
     visit_start_struct(v, NULL, "struct tm", name, 0, errp);
@@ -699,13 +699,19 @@ 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[]) {
+static void rtc_class_initfn(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = rtc_initfn;
+}
+
+static DeviceInfo mc146818rtc_info = {
+    .name     = "mc146818rtc",
+    .size     = sizeof(RTCState),
+    .no_user  = 1,
+    .vmsd     = &vmstate_rtc,
+    .class_init          = rtc_class_initfn,
+    .props    = (Property[]) {
         DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980),
         DEFINE_PROP_END_OF_LIST(),
     }
diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c
index 5bc5f2a..25a7a31 100644
--- a/hw/ne2000-isa.c
+++ b/hw/ne2000-isa.c
@@ -82,11 +82,17 @@ static int isa_ne2000_initfn(ISADevice *dev)
     return 0;
 }
 
-static ISADeviceInfo ne2000_isa_info = {
-    .qdev.name  = "ne2k_isa",
-    .qdev.size  = sizeof(ISANE2000State),
-    .init       = isa_ne2000_initfn,
-    .qdev.props = (Property[]) {
+static void isa_ne2000_class_initfn(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = isa_ne2000_initfn;
+}
+
+static DeviceInfo ne2000_isa_info = {
+    .name  = "ne2k_isa",
+    .size  = sizeof(ISANE2000State),
+    .class_init       = isa_ne2000_class_initfn,
+    .props = (Property[]) {
         DEFINE_PROP_HEX32("iobase", ISANE2000State, iobase, 0x300),
         DEFINE_PROP_UINT32("irq",   ISANE2000State, isairq, 9),
         DEFINE_NIC_PROPERTIES(ISANE2000State, ne2000.c),
diff --git a/hw/parallel.c b/hw/parallel.c
index c4c5dbe..cadcffb 100644
--- a/hw/parallel.c
+++ b/hw/parallel.c
@@ -583,11 +583,17 @@ 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[]) {
+static void parallel_isa_class_initfn(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = parallel_isa_initfn;
+}
+
+static DeviceInfo parallel_isa_info = {
+    .name  = "isa-parallel",
+    .size  = sizeof(ISAParallelState),
+    .class_init       = parallel_isa_class_initfn,
+    .props = (Property[]) {
         DEFINE_PROP_UINT32("index", ISAParallelState, index,   -1),
         DEFINE_PROP_HEX32("iobase", ISAParallelState, iobase,  -1),
         DEFINE_PROP_UINT32("irq",   ISAParallelState, isairq,  7),
diff --git a/hw/pc.c b/hw/pc.c
index f3124d3..31608d3 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -497,13 +497,19 @@ 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)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = port92_initfn;
+}
+
+static DeviceInfo port92_info = {
+    .name     = "port92",
+    .size     = sizeof(Port92State),
+    .vmsd     = &vmstate_port92_isa,
+    .no_user  = 1,
+    .reset    = port92_reset,
+    .class_init          = port92_class_initfn,
 };
 
 static void port92_register(void)
diff --git a/hw/pckbd.c b/hw/pckbd.c
index 06b40c5..2ebe1c5 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -497,12 +497,18 @@ 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)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = i8042_initfn;
+}
+
+static DeviceInfo i8042_info = {
+    .name     = "i8042",
+    .size     = sizeof(ISAKBDState),
+    .vmsd     = &vmstate_kbd_isa,
+    .no_user  = 1,
+    .class_init          = i8042_class_initfn,
 };
 
 static void i8042_register(void)
diff --git a/hw/sb16.c b/hw/sb16.c
index 887b32e..67357ce 100644
--- a/hw/sb16.c
+++ b/hw/sb16.c
@@ -1391,13 +1391,19 @@ 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[]) {
+static void sb16_class_initfn(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = sb16_initfn;
+}
+
+static DeviceInfo sb16_info = {
+    .name     = "sb16",
+    .desc     = "Creative Sound Blaster 16",
+    .size     = sizeof (SB16State),
+    .vmsd     = &vmstate_sb16,
+    .class_init          = sb16_class_initfn,
+    .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),
diff --git a/hw/serial.c b/hw/serial.c
index d35c7a9..2644b13 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -879,12 +879,18 @@ 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[]) {
+static void serial_isa_class_initfn(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = serial_isa_initfn;
+}
+
+static DeviceInfo serial_isa_info = {
+    .name  = "isa-serial",
+    .size  = sizeof(ISASerialState),
+    .vmsd  = &vmstate_isa_serial,
+    .class_init       = serial_isa_class_initfn,
+    .props = (Property[]) {
         DEFINE_PROP_UINT32("index", ISASerialState, index,   -1),
         DEFINE_PROP_HEX32("iobase", ISASerialState, iobase,  -1),
         DEFINE_PROP_UINT32("irq",   ISASerialState, isairq,  -1),
diff --git a/hw/sga.c b/hw/sga.c
index ea11937..d612cb6 100644
--- a/hw/sga.c
+++ b/hw/sga.c
@@ -40,12 +40,17 @@ static int sga_initfn(ISADevice *dev)
     rom_add_vga(SGABIOS_FILENAME);
     return 0;
 }
+static void sga_class_initfn(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = sga_initfn;
+}
 
-static ISADeviceInfo sga_info = {
-    .qdev.name    = "sga",
-    .qdev.desc    = "Serial Graphics Adapter",
-    .qdev.size    = sizeof(ISASGAState),
-    .init         = sga_initfn,
+static DeviceInfo sga_info = {
+    .name    = "sga",
+    .desc    = "Serial Graphics Adapter",
+    .size    = sizeof(ISASGAState),
+    .class_init         = sga_class_initfn,
 };
 
 static void sga_register(void)
diff --git a/hw/vga-isa.c b/hw/vga-isa.c
index 4825313..cb6af91 100644
--- a/hw/vga-isa.c
+++ b/hw/vga-isa.c
@@ -69,12 +69,18 @@ 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)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = vga_initfn;
+}
+
+static DeviceInfo vga_info = {
+    .name     = "isa-vga",
+    .size     = sizeof(ISAVGAState),
+    .vmsd     = &vmstate_vga_common,
+    .reset     = vga_reset_isa,
+    .class_init          = vga_class_initfn,
 };
 
 static void vga_register(void)
diff --git a/hw/vmmouse.c b/hw/vmmouse.c
index 1113f33..da2ea32 100644
--- a/hw/vmmouse.c
+++ b/hw/vmmouse.c
@@ -269,14 +269,20 @@ 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[]) {
+static void vmmouse_class_initfn(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = vmmouse_initfn;
+}
+
+static DeviceInfo vmmouse_info = {
+    .class_init          = vmmouse_class_initfn,
+    .name     = "vmmouse",
+    .size     = sizeof(VMMouseState),
+    .vmsd     = &vmstate_vmmouse,
+    .no_user  = 1,
+    .reset    = vmmouse_reset,
+    .props = (Property[]) {
         DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse),
         DEFINE_PROP_END_OF_LIST(),
     }
diff --git a/hw/vmport.c b/hw/vmport.c
index 0a3dbc5..c4582d6 100644
--- a/hw/vmport.c
+++ b/hw/vmport.c
@@ -144,11 +144,17 @@ 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)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = vmport_initfn;
+}
+
+static DeviceInfo vmport_info = {
+    .name     = "vmport",
+    .size     = sizeof(VMPortState),
+    .no_user  = 1,
+    .class_init          = vmport_class_initfn,
 };
 
 static void vmport_dev_register(void)
diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c
index ba1d92d..6deb0de 100644
--- a/hw/wdt_ib700.c
+++ b/hw/wdt_ib700.c
@@ -120,12 +120,18 @@ 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)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = wdt_ib700_init;
+}
+
+static DeviceInfo wdt_ib700_info = {
+    .name  = "ib700",
+    .size  = sizeof(IB700State),
+    .vmsd  = &vmstate_ib700,
+    .reset = wdt_ib700_reset,
+    .class_init       = wdt_ib700_class_init,
 };
 
 static void wdt_ib700_register_devices(void)
commit e855761ca8fa08ebe29c1e69abc6f0863a453f92
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Tue Dec 6 19:32:44 2011 -0600

    qdev: prepare source tree for code conversion
    
    These are various small stylistic changes which help make things more
    consistent such that the automated conversion script can be simpler.
    
    It's not necessary to agree or disagree with these style changes because all
    of this code is going to be rewritten by the patch monkey script anyway.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 642d5e2..1325f2f 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -172,8 +172,7 @@ static PCIDeviceInfo virtio_9p_info = {
     .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_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),
diff --git a/hw/es1370.c b/hw/es1370.c
index 6a3ba55..3527eb6 100644
--- a/hw/es1370.c
+++ b/hw/es1370.c
@@ -1041,13 +1041,8 @@ static PCIDeviceInfo es1370_info = {
     .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_register (void)
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 5fe98b1..99e7e6f 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -325,27 +325,24 @@ 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 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,
+    /* IDE controller revision */
+    .revision     = 0x07,
+    .class_id     = PCI_CLASS_STORAGE_IDE,
+    .qdev.props   = (Property[]) {
+        DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    },
 };
 
 static void cmd646_ide_register(void)
 {
-    pci_qdev_register_many(cmd646_ide_info);
+    pci_qdev_register(&cmd646_ide_info);
 }
 device_init(cmd646_ide_register);
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 3f7510f..e6421e2 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -146,26 +146,22 @@ 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 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,
 };
 
 static void ich_ahci_register(void)
 {
-    pci_qdev_register_many(ich_ahci_info);
+    pci_qdev_register(&ich_ahci_info);
 }
 device_init(ich_ahci_register);
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index c0e3450..91b77a2 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -237,43 +237,45 @@ 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,
-        .qdev.unplug  = pci_piix3_xen_ide_unplug,
-        .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 PCIDeviceInfo piix3_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,
+};
+
+static PCIDeviceInfo piix3_ide_xen_info = {
+    .qdev.name    = "piix3-ide-xen",
+    .qdev.size    = sizeof(PCIIDEState),
+    .qdev.no_user = 1,
+    .qdev.unplug  = pci_piix3_xen_ide_unplug,
+    .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,
+};
+
+static PCIDeviceInfo piix4_ide_info = {
+    .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,
 };
 
 static void piix_ide_register(void)
 {
-    pci_qdev_register_many(piix_ide_info);
+    pci_qdev_register(&piix3_ide_info);
+    pci_qdev_register(&piix3_ide_xen_info);
+    pci_qdev_register(&piix4_ide_info);
 }
 device_init(piix_ide_register);
diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c
index 0cd8410..409b1eb 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)
@@ -279,11 +279,7 @@ static SysBusDeviceInfo mv88w8618_audio_info = {
     .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),
-        },
+        DEFINE_PROP_PTR("wm8750", mv88w8618_audio_state, wm),
         {/* end of list */}
     }
 };
diff --git a/hw/piix4.c b/hw/piix4.c
index 51af459..130dfd1 100644
--- a/hw/piix4.c
+++ b/hw/piix4.c
@@ -102,25 +102,22 @@ 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 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,
+    /* 82371AB/EB/MB PIIX4 PCI-to-ISA bridge */
+    .device_id    = PCI_DEVICE_ID_INTEL_82371AB_0,
+    .class_id     = PCI_CLASS_BRIDGE_ISA,
 };
 
 static void piix4_register(void)
 {
-    pci_qdev_register_many(piix4_info);
+    pci_qdev_register(&piix4_info);
 }
 device_init(piix4_register);
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 3652522..5cbeed5 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -502,47 +502,47 @@ 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 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,
+};
+
+static PCIDeviceInfo piix3_info = {
+    .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,
+};
+
+static PCIDeviceInfo piix3_xen_info = {
+    .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,
 };
 
 static SysBusDeviceInfo i440fx_pcihost_info = {
@@ -555,7 +555,9 @@ static SysBusDeviceInfo i440fx_pcihost_info = {
 
 static void i440fx_register(void)
 {
+    pci_qdev_register(&i440fx_info);
+    pci_qdev_register(&piix3_info);
+    pci_qdev_register(&piix3_xen_info);
     sysbus_register_withprop(&i440fx_pcihost_info);
-    pci_qdev_register_many(i440fx_info);
 }
 device_init(i440fx_register);
diff --git a/hw/qxl.c b/hw/qxl.c
index 6442193..a00dc33 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1824,7 +1824,7 @@ static Property qxl_properties[] = {
         DEFINE_PROP_END_OF_LIST(),
 };
 
-static PCIDeviceInfo qxl_info_primary = {
+static PCIDeviceInfo qxl_primary_info = {
     .qdev.name    = "qxl-vga",
     .qdev.desc    = "Spice QXL GPU (primary, vga compatible)",
     .qdev.size    = sizeof(PCIQXLDevice),
@@ -1839,7 +1839,7 @@ static PCIDeviceInfo qxl_info_primary = {
     .qdev.props   = qxl_properties,
 };
 
-static PCIDeviceInfo qxl_info_secondary = {
+static PCIDeviceInfo qxl_secondary_info = {
     .qdev.name    = "qxl",
     .qdev.desc    = "Spice QXL GPU (secondary)",
     .qdev.size    = sizeof(PCIQXLDevice),
@@ -1854,8 +1854,8 @@ static PCIDeviceInfo qxl_info_secondary = {
 
 static void qxl_register(void)
 {
-    pci_qdev_register(&qxl_info_primary);
-    pci_qdev_register(&qxl_info_secondary);
+    pci_qdev_register(&qxl_primary_info);
+    pci_qdev_register(&qxl_secondary_info);
 }
 
 device_init(qxl_register);
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
index 91003cc..b9a5afc 100644
--- a/hw/spapr_llan.c
+++ b/hw/spapr_llan.c
@@ -474,7 +474,7 @@ static target_ulong h_multicast_ctrl(CPUState *env, sPAPREnvironment *spapr,
     return H_SUCCESS;
 }
 
-static VIOsPAPRDeviceInfo spapr_vlan = {
+static VIOsPAPRDeviceInfo spapr_vlan_info = {
     .init = spapr_vlan_init,
     .devnode = spapr_vlan_devnode,
     .dt_name = "l-lan",
@@ -492,12 +492,12 @@ static VIOsPAPRDeviceInfo spapr_vlan = {
 
 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);
+    spapr_vio_bus_register_withprop(&spapr_vlan_info);
 }
 device_init(spapr_vlan_register);
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 00e2d2d..21d946e 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -947,7 +947,7 @@ static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
     return 0;
 }
 
-static VIOsPAPRDeviceInfo spapr_vscsi = {
+static VIOsPAPRDeviceInfo spapr_vscsi_info = {
     .init = spapr_vscsi_init,
     .devnode = spapr_vscsi_devnode,
     .dt_name = "v-scsi",
@@ -964,6 +964,6 @@ static VIOsPAPRDeviceInfo spapr_vscsi = {
 
 static void spapr_vscsi_register(void)
 {
-    spapr_vio_bus_register_withprop(&spapr_vscsi);
+    spapr_vio_bus_register_withprop(&spapr_vscsi_info);
 }
 device_init(spapr_vscsi_register);
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index 181dd0e..3d5c579 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -135,7 +135,7 @@ void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev)
     qdev_init_nofail(dev);
 }
 
-static VIOsPAPRDeviceInfo spapr_vty = {
+static VIOsPAPRDeviceInfo spapr_vty_info = {
     .init = spapr_vty_init,
     .dt_name = "vty",
     .dt_type = "serial",
@@ -163,7 +163,7 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
     selected = NULL;
     QTAILQ_FOREACH(iter, &bus->bus.children, sibling) {
         /* Only look at VTY devices */
-        if (qdev_get_info(iter) != &spapr_vty.qdev) {
+        if (qdev_get_info(iter) != &spapr_vty_info.qdev) {
             continue;
         }
 
@@ -203,8 +203,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);
+    spapr_vio_bus_register_withprop(&spapr_vty_info);
 }
 device_init(spapr_vty_register);
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index a305661..63fc3c7 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -2263,30 +2263,28 @@ 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 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,
+};
+
+static PCIDeviceInfo ich9_ehci_info = {
+    .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,
 };
 
 static int usb_ehci_initfn(PCIDevice *dev)
@@ -2362,7 +2360,8 @@ static int usb_ehci_initfn(PCIDevice *dev)
 
 static void ehci_register(void)
 {
-    pci_qdev_register_many(ehci_info);
+    pci_qdev_register(&ehci_info);
+    pci_qdev_register(&ich9_ehci_info);
 }
 device_init(ehci_register);
 
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 25d4e8c..1821063 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -1192,8 +1192,7 @@ static Property uhci_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static PCIDeviceInfo uhci_info[] = {
-    {
+static PCIDeviceInfo piix3_uhci_info = {
         .qdev.name    = "piix3-usb-uhci",
         .qdev.size    = sizeof(UHCIState),
         .qdev.vmsd    = &vmstate_uhci,
@@ -1204,7 +1203,9 @@ static PCIDeviceInfo uhci_info[] = {
         .revision     = 0x01,
         .class_id     = PCI_CLASS_SERIAL_USB,
         .qdev.props   = uhci_properties,
-    },{
+};
+
+static PCIDeviceInfo piix4_uhci_info = {
         .qdev.name    = "piix4-usb-uhci",
         .qdev.size    = sizeof(UHCIState),
         .qdev.vmsd    = &vmstate_uhci,
@@ -1215,55 +1216,65 @@ static PCIDeviceInfo uhci_info[] = {
         .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 PCIDeviceInfo vt82c686b_uhci_info = {
+    .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,
+};
+
+static PCIDeviceInfo ich9_uhci1_info = {
+    .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,
+};
+
+static PCIDeviceInfo ich9_uhci2_info = {
+    .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,
+};
+
+static PCIDeviceInfo ich9_uhci3_info = {
+    .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,
 };
 
 static void uhci_register(void)
 {
-    pci_qdev_register_many(uhci_info);
+    pci_qdev_register(&piix3_uhci_info);
+    pci_qdev_register(&piix4_uhci_info);
+    pci_qdev_register(&vt82c686b_uhci_info);
+    pci_qdev_register(&ich9_uhci1_info);
+    pci_qdev_register(&ich9_uhci2_info);
+    pci_qdev_register(&ich9_uhci3_info);
 }
 device_init(uhci_register);
 
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index c93889a..72b53af 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -806,98 +806,96 @@ 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 PCIDeviceInfo virtio_blk_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,
+};
+
+static PCIDeviceInfo virtio_net_info = {
+    .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,
+};
+
+static PCIDeviceInfo virtio_serial_info = {
+    .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,
+};
+
+static PCIDeviceInfo virtio_balloon_info = {
+    .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,
 };
 
 static void virtio_pci_register_devices(void)
 {
-    pci_qdev_register_many(virtio_info);
+    pci_qdev_register(&virtio_blk_info);
+    pci_qdev_register(&virtio_net_info);
+    pci_qdev_register(&virtio_serial_info);
+    pci_qdev_register(&virtio_balloon_info);
 }
 
 device_init(virtio_pci_register_devices)
commit 3dde52d2fe5fd4783bdd06f88561cbd0695aae06
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Sun Dec 4 14:37:06 2011 -0600

    qdev: add class_init to DeviceInfo
    
    Since we are still dynamically creating TypeInfo, we need to chain the
    class_init function in order to be able to make use of it within subclasses of
    TYPE_DEVICE.
    
    This will disappear once we register TypeInfos directly.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev.c b/hw/qdev.c
index c4b5284..81996bb 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -54,6 +54,10 @@ static void qdev_subclass_init(ObjectClass *klass, void *data)
 
     /* Poison to try to detect future uses */
     dc->info->reset = NULL;
+
+    if (dc->info->class_init) {
+        dc->info->class_init(klass, data);
+    }
 }
 
 DeviceInfo *qdev_get_info(DeviceState *dev)
diff --git a/hw/qdev.h b/hw/qdev.h
index 48f80a5..c9572a5 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -231,6 +231,11 @@ struct DeviceInfo {
     /* device state */
     const VMStateDescription *vmsd;
 
+    /**
+     * See #TypeInfo::class_init()
+     */
+    void (*class_init)(ObjectClass *klass, void *data);
+
     /* Private to qdev / bus.  */
     qdev_initfn init;
     qdev_event unplug;
commit 3cc90eb2b7c0810fb23ceed57c1f50683ee803fd
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Dec 15 14:40:29 2011 -0600

    qdev: add a interface to register subclasses
    
    In order to introduce inheritance while still using the qdev registration
    interfaces, we need to be able to use a parent other than TYPE_DEVICE.  Add a
    new interface that allows this.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev.c b/hw/qdev.c
index a80ca7c..c4b5284 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -61,7 +61,7 @@ DeviceInfo *qdev_get_info(DeviceState *dev)
     return DEVICE_GET_CLASS(dev)->info;
 }
 
-void qdev_register(DeviceInfo *info)
+void qdev_register_subclass(DeviceInfo *info, const char *parent)
 {
     TypeInfo type_info = {};
 
@@ -69,7 +69,7 @@ void qdev_register(DeviceInfo *info)
     assert(!info->next);
 
     type_info.name = info->name;
-    type_info.parent = TYPE_DEVICE;
+    type_info.parent = parent;
     type_info.instance_size = info->size;
     type_info.class_init = qdev_subclass_init;
     type_info.class_data = info;
@@ -80,6 +80,11 @@ void qdev_register(DeviceInfo *info)
     device_info_list = info;
 }
 
+void qdev_register(DeviceInfo *info)
+{
+    qdev_register_subclass(info, TYPE_DEVICE);
+}
+
 static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
 {
     DeviceInfo *info;
diff --git a/hw/qdev.h b/hw/qdev.h
index f3c9219..48f80a5 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -241,6 +241,7 @@ struct DeviceInfo {
 extern DeviceInfo *device_info_list;
 
 void qdev_register(DeviceInfo *info);
+void qdev_register_subclass(DeviceInfo *info, const char *parent);
 
 /* Register device properties.  */
 /* GPIO inputs also double as IRQ sinks.  */
commit 94afdadcb3ab71f5123f719d74065c6f4cc837ea
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Sun Dec 4 11:36:01 2011 -0600

    qdev: use a wrapper to access reset and promote reset to a class method
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 8cb92d3..6e1c5de 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -1116,9 +1116,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_get_info(qdev)->reset) {
-            qdev_get_info(qdev)->reset(qdev);
-        }
+        device_reset(DEVICE(cdev));
         d->state_sts |= (1 << cdev->cad);
     }
     intel_hda_update_irq(d);
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 9f475e0..3a87171 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) {
-                    qdev_get_info(dev)->reset(dev);
+                    device_reset(dev);
                 }
                 s->sstat0 |= LSI_SSTAT0_RST;
                 lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
diff --git a/hw/qdev.c b/hw/qdev.c
index 5da94a8..a80ca7c 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -48,7 +48,12 @@ static BusState *qbus_find(const char *path);
 static void qdev_subclass_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
+
     dc->info = data;
+    dc->reset = dc->info->reset;
+
+    /* Poison to try to detect future uses */
+    dc->info->reset = NULL;
 }
 
 DeviceInfo *qdev_get_info(DeviceState *dev)
@@ -378,8 +383,8 @@ int qdev_init(DeviceState *dev)
                                        dev->alias_required_for_version);
     }
     dev->state = DEV_STATE_INITIALIZED;
-    if (dev->hotplugged && qdev_get_info(dev)->reset) {
-        qdev_get_info(dev)->reset(dev);
+    if (dev->hotplugged) {
+        device_reset(dev);
     }
     return 0;
 }
@@ -407,9 +412,7 @@ int qdev_unplug(DeviceState *dev)
 
 static int qdev_reset_one(DeviceState *dev, void *opaque)
 {
-    if (qdev_get_info(dev)->reset) {
-        qdev_get_info(dev)->reset(dev);
-    }
+    device_reset(dev);
 
     return 0;
 }
@@ -1593,6 +1596,15 @@ void qdev_machine_init(void)
     qdev_get_peripheral();
 }
 
+void device_reset(DeviceState *dev)
+{
+    DeviceClass *klass = DEVICE_GET_CLASS(dev);
+
+    if (klass->reset) {
+        klass->reset(dev);
+    }
+}
+
 static TypeInfo device_type_info = {
     .name = TYPE_DEVICE,
     .parent = TYPE_OBJECT,
diff --git a/hw/qdev.h b/hw/qdev.h
index a6af632..f3c9219 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -75,6 +75,7 @@ typedef struct DeviceProperty
 typedef struct DeviceClass {
     ObjectClass parent_class;
     DeviceInfo *info;
+    void (*reset)(DeviceState *dev);
 } DeviceClass;
 
 /* This structure should not be accessed directly.  We declare it here
@@ -647,4 +648,11 @@ char *qdev_get_type(DeviceState *dev, Error **errp);
  */
 void qdev_machine_init(void);
 
+/**
+ * @device_reset
+ *
+ * Reset a single device (by calling the reset method).
+ */
+void device_reset(DeviceState *dev);
+
 #endif
commit f79f2bfc6aae76718652f0b3e15a849f7b58104a
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Sun Dec 4 11:17:51 2011 -0600

    qdev: don't access name through info
    
    We already have a QOM interface for this so let's use it.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/e1000.c b/hw/e1000.c
index e4362ea..7fc7318 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -1182,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,
-                          qdev_get_info(&d->dev.qdev)->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);
 
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 81a32b8..f0059c6 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -1878,7 +1878,7 @@ static int e100_nic_init(PCIDevice *pci_dev)
     nic_reset(s);
 
     s->nic = qemu_new_nic(&net_eepro100_info, &s->conf,
-                          qdev_get_info(&pci_dev->qdev)->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));
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index 5afa55f..1b6b71d 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);
diff --git a/hw/hda-audio.c b/hw/hda-audio.c
index 0bc0a25..8053c74 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 = qdev_get_info(&a->hda.qdev)->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);
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 12dcc84..8cb92d3 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -1129,7 +1129,7 @@ static int intel_hda_init(PCIDevice *pci)
     IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
     uint8_t *conf = d->pci.config;
 
-    d->name = qdev_get_info(&d->pci.qdev)->name;
+    d->name = object_get_typename(OBJECT(d));
 
     pci_config_set_interrupt_pin(conf, 1);
 
diff --git a/hw/lan9118.c b/hw/lan9118.c
index d1b244e..93e1896 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -1221,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,
-                          qdev_get_info(&dev->qdev)->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++) {
diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c
index 7006d29..107ba65 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;
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index 1486833..0f80cfe 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,
-                          qdev_get_info(&dev->qdev)->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;
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 977ffb6..bca5ee9 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);
diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c
index 60dc333..5bc5f2a 100644
--- a/hw/ne2000-isa.c
+++ b/hw/ne2000-isa.c
@@ -76,7 +76,7 @@ static int isa_ne2000_initfn(ISADevice *dev)
     ne2000_reset(s);
 
     s->nic = qemu_new_nic(&net_ne2000_isa_info, &s->c,
-                          qdev_get_info(&dev->qdev)->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;
diff --git a/hw/ne2000.c b/hw/ne2000.c
index d016b8e..b44eab1 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,
-                          qdev_get_info(&pci_dev->qdev)->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) {
diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c
index d4d3529..5161b0c 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,
-                          qdev_get_info(&s->dev.qdev)->name, s->dev.qdev.id, s);
+                          object_get_typename(OBJECT(s)), s->dev.qdev.id, s);
     return 0;
 }
 
diff --git a/hw/pci.c b/hw/pci.c
index 5345079..516da08 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1493,7 +1493,7 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
     if (pci_dev == NULL)
         return -1;
     if (qdev->hotplugged && info->no_hotplug) {
-        qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
+        qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(pci_dev)));
         do_pci_unregister_device(pci_dev);
         return -1;
     }
@@ -1534,7 +1534,7 @@ static int pci_unplug_device(DeviceState *qdev)
     PCIDeviceInfo *info = container_of(qdev_get_info(qdev), PCIDeviceInfo, qdev);
 
     if (info->no_hotplug) {
-        qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
+        qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev)));
         return -1;
     }
     return dev->bus->hotplug(dev->bus->hotplug_qdev, dev,
@@ -1742,7 +1742,7 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
     if (qdev_get_info(&pdev->qdev)->vmsd)
         snprintf(name, sizeof(name), "%s.rom", qdev_get_info(&pdev->qdev)->vmsd->name);
     else
-        snprintf(name, sizeof(name), "%s.rom", qdev_get_info(&pdev->qdev)->name);
+        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);
diff --git a/hw/pcnet.c b/hw/pcnet.c
index 54f14ee..c53f06e 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -1718,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, qdev_get_info(dev)->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 at 0");
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index d71dfda..c98219a 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -989,16 +989,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,
-                  qdev_get_info(dev)->name, prop->name, value);
+                  object_get_typename(OBJECT(dev)), prop->name, value);
         break;
     default:
     case -EINVAL:
         error_set(errp, QERR_PROPERTY_VALUE_BAD,
-                  qdev_get_info(dev)->name, prop->name, value);
+                  object_get_typename(OBJECT(dev)), prop->name, value);
         break;
     case -ENOENT:
         error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND,
-                  qdev_get_info(dev)->name, prop->name, value);
+                  object_get_typename(OBJECT(dev)), prop->name, value);
         break;
     case 0:
         break;
@@ -1018,7 +1018,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, qdev_get_info(dev)->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 +1039,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__, qdev_get_info(dev)->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__, qdev_get_info(dev)->name, name);
+                __FUNCTION__, object_get_typename(OBJECT(dev)), name);
         abort();
     }
     qdev_prop_cpy(dev, prop, src);
@@ -1093,7 +1093,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 : qdev_get_info(dev)->name,
+                     dev->id ? dev->id : object_get_typename(OBJECT(dev)),
                      name, strerror(-res));
         return -1;
     }
@@ -1165,7 +1165,7 @@ void qdev_prop_set_globals(DeviceState *dev)
     GlobalProperty *prop;
 
     QTAILQ_FOREACH(prop, &global_props, next) {
-        if (strcmp(qdev_get_info(dev)->name, prop->driver) != 0 &&
+        if (strcmp(object_get_typename(OBJECT(dev)), prop->driver) != 0 &&
             strcmp(qdev_get_info(dev)->bus_info->name, prop->driver) != 0) {
             continue;
         }
diff --git a/hw/qdev.c b/hw/qdev.c
index 49d26a2..5da94a8 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -720,7 +720,7 @@ static void qbus_list_bus(DeviceState *dev)
     const char *sep = " ";
 
     error_printf("child busses at \"%s\":",
-                 dev->id ? dev->id : qdev_get_info(dev)->name);
+                 dev->id ? dev->id : object_get_typename(OBJECT(dev)));
     QLIST_FOREACH(child, &dev->child_bus, sibling) {
         error_printf("%s\"%s\"", sep, child->name);
         sep = ", ";
@@ -735,7 +735,7 @@ static void qbus_list_dev(BusState *bus)
 
     error_printf("devices at \"%s\":", bus->name);
     QTAILQ_FOREACH(dev, &bus->children, sibling) {
-        error_printf("%s\"%s\"", sep, qdev_get_info(dev)->name);
+        error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev)));
         if (dev->id)
             error_printf("/\"%s\"", dev->id);
         sep = ", ";
@@ -771,7 +771,7 @@ static DeviceState *qbus_find_dev(BusState *bus, char *elem)
         }
     }
     QTAILQ_FOREACH(dev, &bus->children, sibling) {
-        if (strcmp(qdev_get_info(dev)->name, elem) == 0) {
+        if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) {
             return dev;
         }
     }
@@ -978,7 +978,7 @@ static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
 static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
 {
     BusState *child;
-    qdev_printf("dev: %s, id \"%s\"\n", qdev_get_info(dev)->name,
+    qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)),
                 dev->id ? dev->id : "");
     indent += 2;
     if (dev->num_gpio_in) {
@@ -1068,7 +1068,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", qdev_get_info(dev)->name);
+            l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(dev)));
         }
     }
     l += snprintf(p + l , size - l, "/");
@@ -1090,7 +1090,7 @@ char* qdev_get_fw_dev_path(DeviceState *dev)
 
 char *qdev_get_type(DeviceState *dev, Error **errp)
 {
-    return g_strdup(qdev_get_info(dev)->name);
+    return g_strdup(object_get_typename(OBJECT(dev)));
 }
 
 void qdev_ref(DeviceState *dev)
@@ -1300,7 +1300,7 @@ void qdev_property_add_child(DeviceState *dev, const char *name,
 {
     gchar *type;
 
-    type = g_strdup_printf("child<%s>", qdev_get_info(child)->name);
+    type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
 
     qdev_property_add(dev, name, type, qdev_get_child_property,
                       NULL, qdev_release_child_property,
@@ -1352,7 +1352,7 @@ static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque,
         if (target) {
             gchar *target_type;
 
-            target_type = g_strdup_printf("link<%s>", qdev_get_info(target)->name);
+            target_type = g_strdup_printf("link<%s>", object_get_typename(OBJECT(target)));
             if (strcmp(target_type, type) == 0) {
                 *child = target;
                 qdev_ref(target);
diff --git a/hw/qdev.h b/hw/qdev.h
index e13111f..a6af632 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -403,7 +403,7 @@ static inline const char *qdev_fw_name(DeviceState *dev)
         return info->alias;
     }
 
-    return info->name;
+    return object_get_typename(OBJECT(dev));
 }
 
 char *qdev_get_fw_dev_path(DeviceState *dev);
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 16d948e..2b55c7f 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,
-                          qdev_get_info(&dev->qdev)->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;
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index b83a893..4a68f6b 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -752,7 +752,7 @@ 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,
-                          qdev_get_info(&dev->qdev)->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;
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
index 45674c4..91003cc 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;
diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c
index 866c9a2..ecd750c 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);
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index 3b80d5e..9b67f18 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -250,7 +250,7 @@ int usb_claim_port(USBDevice *dev)
             return -1;
         }
     } else {
-        if (bus->nfree == 1 && strcmp(qdev_get_info(&dev->qdev)->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");
         }
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 086aa7e..fd4106b 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1337,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,
-                          qdev_get_info(&s->dev.qdev)->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",
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index afa3274..2df6a6e 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1777,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 = qdev_get_info(dev)->name;
+    ohci->name = object_get_typename(OBJECT(dev));
     usb_packet_init(&ohci->usb_packet);
 
     ohci->async_td = 0;
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 6c785d0..bc5e3a8 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, qdev_get_info(dev)->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/xgmac.c b/hw/xgmac.c
index ccb9759..ef0ca24 100644
--- a/hw/xgmac.c
+++ b/hw/xgmac.c
@@ -390,7 +390,7 @@ static int xgmac_enet_init(SysBusDevice *dev)
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     s->nic = qemu_new_nic(&net_xgmac_enet_info, &s->conf,
-                          qdev_get_info(&dev->qdev)->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->regs[XGMAC_ADDR_HIGH(0)] = (s->conf.macaddr.a[5] << 8) |
diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
index a2eb3e6..e713248 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);
diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c
index 6777254..de595f4 100644
--- a/hw/xilinx_ethlite.c
+++ b/hw/xilinx_ethlite.c
@@ -221,7 +221,7 @@ 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;
 }
commit 30fbb9fc7cd73abc32ff71ceb59e9a3be37ac128
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Sun Dec 4 11:08:36 2011 -0600

    qdev: move qdev->info to class
    
    Right now, DeviceInfo acts as the class for qdev.  In order to switch to a
    proper ObjectClass derivative, we need to ween all of the callers off of
    interacting directly with the info pointer.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index bdc55a1..4d0b390 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -280,7 +280,7 @@ 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);
+        PCIDeviceInfo *info = container_of(qdev_get_info(qdev), PCIDeviceInfo, qdev);
         PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
         int slot = PCI_SLOT(pdev->devfn);
 
@@ -491,7 +491,7 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
 
     QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
         dev = DO_UPCAST(PCIDevice, qdev, qdev);
-        info = container_of(qdev->info, PCIDeviceInfo, qdev);
+        info = container_of(qdev_get_info(qdev), PCIDeviceInfo, qdev);
         if (PCI_SLOT(dev->devfn) == slot && !info->no_hotplug) {
             qdev_free(qdev);
         }
diff --git a/hw/apic_common.c b/hw/apic_common.c
index e05369c..ac06147 100644
--- a/hw/apic_common.c
+++ b/hw/apic_common.c
@@ -31,7 +31,7 @@ void cpu_set_apic_base(DeviceState *d, uint64_t val)
     trace_cpu_set_apic_base(val);
 
     if (s) {
-        info = DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+        info = DO_UPCAST(APICCommonInfo, busdev.qdev, qdev_get_info(&s->busdev.qdev));
         info->set_base(s, val);
     }
 }
@@ -51,7 +51,7 @@ void cpu_set_apic_tpr(DeviceState *d, uint8_t val)
     APICCommonInfo *info;
 
     if (s) {
-        info = DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+        info = DO_UPCAST(APICCommonInfo, busdev.qdev, qdev_get_info(&s->busdev.qdev));
         info->set_tpr(s, val);
     }
 }
@@ -89,7 +89,7 @@ void apic_deliver_nmi(DeviceState *d)
     APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
     APICCommonInfo *info;
 
-    info = DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+    info = DO_UPCAST(APICCommonInfo, busdev.qdev, qdev_get_info(&s->busdev.qdev));
     info->external_nmi(s);
 }
 
@@ -232,7 +232,7 @@ static int apic_init_common(SysBusDevice *dev)
     }
     s->idx = apic_no++;
 
-    info = DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+    info = DO_UPCAST(APICCommonInfo, busdev.qdev, qdev_get_info(&s->busdev.qdev));
     info->init(s);
 
     sysbus_init_mmio(&s->busdev, &s->io_memory);
@@ -243,7 +243,7 @@ static int apic_dispatch_post_load(void *opaque, int version_id)
 {
     APICCommonState *s = opaque;
     APICCommonInfo *info =
-        DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+        DO_UPCAST(APICCommonInfo, busdev.qdev, qdev_get_info(&s->busdev.qdev));
 
     if (info->post_load) {
         info->post_load(s);
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 7ce35ec..5b22cc3 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2921,7 +2921,7 @@ 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);
+     PCIDeviceInfo *info = DO_UPCAST(PCIDeviceInfo, qdev, qdev_get_info(&dev->qdev));
      int16_t device_id = info->device_id;
 
      /* setup VGA */
diff --git a/hw/e1000.c b/hw/e1000.c
index 76e736f..e4362ea 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -1182,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);
+                          qdev_get_info(&d->dev.qdev)->name, d->dev.qdev.id, d);
 
     qemu_format_nic_info_str(&d->nic->nc, macaddr);
 
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 6a162f6..81a32b8 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -1848,7 +1848,7 @@ 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);
+                                               qdev_get_info(&pci_dev->qdev));
 
     TRACE(OTHER, logout("\n"));
 
@@ -1878,7 +1878,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);
+                          qdev_get_info(&pci_dev->qdev)->name, 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));
diff --git a/hw/hda-audio.c b/hw/hda-audio.c
index 9b089e6..0bc0a25 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 = qdev_get_info(&a->hda.qdev)->name;
     dprint(a, 1, "%s: cad %d\n", __FUNCTION__, a->hda.cad);
 
     AUD_register_card("hda", &a->card);
diff --git a/hw/i8259_common.c b/hw/i8259_common.c
index e515876..7536897 100644
--- a/hw/i8259_common.c
+++ b/hw/i8259_common.c
@@ -49,7 +49,7 @@ static void pic_dispatch_pre_save(void *opaque)
 {
     PICCommonState *s = opaque;
     PICCommonInfo *info =
-        DO_UPCAST(PICCommonInfo, isadev.qdev, s->dev.qdev.info);
+        DO_UPCAST(PICCommonInfo, isadev.qdev, qdev_get_info(&s->dev.qdev));
 
     if (info->pre_save) {
         info->pre_save(s);
@@ -60,7 +60,7 @@ static int pic_dispatch_post_load(void *opaque, int version_id)
 {
     PICCommonState *s = opaque;
     PICCommonInfo *info =
-        DO_UPCAST(PICCommonInfo, isadev.qdev, s->dev.qdev.info);
+        DO_UPCAST(PICCommonInfo, isadev.qdev, qdev_get_info(&s->dev.qdev));
 
     if (info->post_load) {
         info->post_load(s);
@@ -72,7 +72,7 @@ static int pic_init_common(ISADevice *dev)
 {
     PICCommonState *s = DO_UPCAST(PICCommonState, dev, dev);
     PICCommonInfo *info =
-        DO_UPCAST(PICCommonInfo, isadev.qdev, dev->qdev.info);
+        DO_UPCAST(PICCommonInfo, isadev.qdev, qdev_get_info(&dev->qdev));
 
     info->init(s);
 
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 3473345..c0e3450 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;
 }
@@ -253,6 +252,7 @@ static PCIDeviceInfo piix_ide_info[] = {
         .qdev.name    = "piix3-ide-xen",
         .qdev.size    = sizeof(PCIIDEState),
         .qdev.no_user = 1,
+        .qdev.unplug  = pci_piix3_xen_ide_unplug,
         .init         = pci_piix_ide_initfn,
         .vendor_id    = PCI_VENDOR_ID_INTEL,
         .device_id    = PCI_DEVICE_ID_INTEL_82371SB_1,
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 10769e0..12dcc84 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -1116,8 +1116,8 @@ 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);
+        if (qdev_get_info(qdev)->reset) {
+            qdev_get_info(qdev)->reset(qdev);
         }
         d->state_sts |= (1 << cdev->cad);
     }
@@ -1129,7 +1129,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 = qdev_get_info(&d->pci.qdev)->name;
 
     pci_config_set_interrupt_pin(conf, 1);
 
diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c
index 3aa9a1c..4a7624c 100644
--- a/hw/ioapic_common.c
+++ b/hw/ioapic_common.c
@@ -40,7 +40,7 @@ static void ioapic_dispatch_pre_save(void *opaque)
 {
     IOAPICCommonState *s = opaque;
     IOAPICCommonInfo *info =
-        DO_UPCAST(IOAPICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+        DO_UPCAST(IOAPICCommonInfo, busdev.qdev, qdev_get_info(&s->busdev.qdev));
 
     if (info->pre_save) {
         info->pre_save(s);
@@ -51,7 +51,7 @@ static int ioapic_dispatch_post_load(void *opaque, int version_id)
 {
     IOAPICCommonState *s = opaque;
     IOAPICCommonInfo *info =
-        DO_UPCAST(IOAPICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+        DO_UPCAST(IOAPICCommonInfo, busdev.qdev, qdev_get_info(&s->busdev.qdev));
 
     if (info->post_load) {
         info->post_load(s);
@@ -69,7 +69,7 @@ static int ioapic_init_common(SysBusDevice *dev)
         return -1;
     }
 
-    info = DO_UPCAST(IOAPICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+    info = DO_UPCAST(IOAPICCommonInfo, busdev.qdev, qdev_get_info(&s->busdev.qdev));
     info->init(s, ioapic_no);
 
     sysbus_init_mmio(&s->busdev, &s->io_memory);
diff --git a/hw/lan9118.c b/hw/lan9118.c
index 9b199d0..d1b244e 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -1221,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);
+                          qdev_get_info(&dev->qdev)->name, 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++) {
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 0d3a101..9f475e0 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);
+                    qdev_get_info(dev)->reset(dev);
                 }
                 s->sstat0 |= LSI_SSTAT0_RST;
                 lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index b1234b8..1486833 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);
+                          qdev_get_info(&dev->qdev)->name, dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
 
     return 0;
diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c
index 11ffee7..60dc333 100644
--- a/hw/ne2000-isa.c
+++ b/hw/ne2000-isa.c
@@ -76,7 +76,7 @@ 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);
+                          qdev_get_info(&dev->qdev)->name, dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a);
 
     return 0;
diff --git a/hw/ne2000.c b/hw/ne2000.c
index 62e082f..d016b8e 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);
+                          qdev_get_info(&pci_dev->qdev)->name, pci_dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a);
 
     if (!pci_dev->qdev.hotplugged) {
diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c
index f7cc1b4..d4d3529 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);
+                          qdev_get_info(&s->dev.qdev)->name, s->dev.qdev.id, s);
     return 0;
 }
 
diff --git a/hw/pci.c b/hw/pci.c
index ab3b53d..5345079 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -841,7 +841,7 @@ 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);
+    PCIDeviceInfo *info = DO_UPCAST(PCIDeviceInfo, qdev, qdev_get_info(dev));
     int ret = 0;
 
     if (info->exit)
@@ -1531,7 +1531,7 @@ 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);
+    PCIDeviceInfo *info = container_of(qdev_get_info(qdev), PCIDeviceInfo, qdev);
 
     if (info->no_hotplug) {
         qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
@@ -1544,7 +1544,9 @@ static int pci_unplug_device(DeviceState *qdev)
 void pci_qdev_register(PCIDeviceInfo *info)
 {
     info->qdev.init = pci_qdev_init;
-    info->qdev.unplug = pci_unplug_device;
+    if (!info->qdev.unplug) {
+        info->qdev.unplug = pci_unplug_device;
+    }
     info->qdev.exit = pci_unregister_device;
     info->qdev.bus_info = &pci_bus_info;
     qdev_register(&info->qdev);
@@ -1737,10 +1739,10 @@ 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);
+    if (qdev_get_info(&pdev->qdev)->vmsd)
+        snprintf(name, sizeof(name), "%s.rom", qdev_get_info(&pdev->qdev)->vmsd->name);
     else
-        snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->name);
+        snprintf(name, sizeof(name), "%s.rom", qdev_get_info(&pdev->qdev)->name);
     pdev->has_rom = true;
     memory_region_init_ram(&pdev->rom, name, size);
     vmstate_register_ram(&pdev->rom, &pdev->qdev);
@@ -1981,7 +1983,7 @@ static int pci_qdev_find_recursive(PCIBus *bus,
     }
 
     /* roughly check if given qdev is pci device */
-    if (qdev->info->init == &pci_qdev_init &&
+    if (qdev_get_info(qdev)->init == &pci_qdev_init &&
         qdev->parent_bus->info == &pci_bus_info) {
         *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
         return 0;
diff --git a/hw/pcnet.c b/hw/pcnet.c
index 6aa48e0..54f14ee 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -1718,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, qdev_get_info(dev)->name, 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 at 0");
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index ea3b2df..d71dfda 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -966,7 +966,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_info(dev)->props, name);
     if (prop)
         return prop;
 
@@ -989,16 +989,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);
+                  qdev_get_info(dev)->name, prop->name, value);
         break;
     default:
     case -EINVAL:
         error_set(errp, QERR_PROPERTY_VALUE_BAD,
-                  dev->info->name, prop->name, value);
+                  qdev_get_info(dev)->name, prop->name, value);
         break;
     case -ENOENT:
         error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND,
-                  dev->info->name, prop->name, value);
+                  qdev_get_info(dev)->name, prop->name, value);
         break;
     case 0:
         break;
@@ -1018,7 +1018,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, qdev_get_info(dev)->name, name);
         return -1;
     }
     ret = prop->info->parse(dev, prop, value);
@@ -1039,12 +1039,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__, qdev_get_info(dev)->name, name);
         abort();
     }
     if (prop->info->type != type) {
         fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n",
-                __FUNCTION__, dev->info->name, name);
+                __FUNCTION__, qdev_get_info(dev)->name, name);
         abort();
     }
     qdev_prop_cpy(dev, prop, src);
@@ -1093,7 +1093,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 : qdev_get_info(dev)->name,
                      name, strerror(-res));
         return -1;
     }
@@ -1165,8 +1165,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(qdev_get_info(dev)->name, prop->driver) != 0 &&
+            strcmp(qdev_get_info(dev)->bus_info->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 3bc9166..49d26a2 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -45,6 +45,17 @@ static BusState *qbus_find_recursive(BusState *bus, const char *name,
 static BusState *qbus_find(const char *path);
 
 /* Register a new device type.  */
+static void qdev_subclass_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->info = data;
+}
+
+DeviceInfo *qdev_get_info(DeviceState *dev)
+{
+    return DEVICE_GET_CLASS(dev)->info;
+}
+
 void qdev_register(DeviceInfo *info)
 {
     TypeInfo type_info = {};
@@ -55,6 +66,8 @@ void qdev_register(DeviceInfo *info)
     type_info.name = info->name;
     type_info.parent = TYPE_DEVICE;
     type_info.instance_size = info->size;
+    type_info.class_init = qdev_subclass_init;
+    type_info.class_data = info;
 
     type_register_static(&type_info);
 
@@ -102,9 +115,8 @@ static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
 
     assert(bus->info == info->bus_info);
     dev = DEVICE(object_new(info->name));
-    dev->info = info;
     dev->parent_bus = bus;
-    qdev_prop_set_defaults(dev, dev->info->props);
+    qdev_prop_set_defaults(dev, qdev_get_info(dev)->props);
     qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
     qdev_prop_set_globals(dev);
     QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
@@ -117,12 +129,12 @@ static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
     QTAILQ_INIT(&dev->properties);
     dev->state = DEV_STATE_CREATED;
 
-    for (prop = dev->info->props; prop && prop->name; prop++) {
+    for (prop = qdev_get_info(dev)->props; prop && prop->name; prop++) {
         qdev_property_add_legacy(dev, prop, NULL);
         qdev_property_add_static(dev, prop, NULL);
     }
 
-    for (prop = dev->info->bus_info->props; prop && prop->name; prop++) {
+    for (prop = qdev_get_info(dev)->bus_info->props; prop && prop->name; prop++) {
         qdev_property_add_legacy(dev, prop, NULL);
         qdev_property_add_static(dev, prop, NULL);
     }
@@ -355,19 +367,19 @@ int qdev_init(DeviceState *dev)
     int rc;
 
     assert(dev->state == DEV_STATE_CREATED);
-    rc = dev->info->init(dev, dev->info);
+    rc = qdev_get_info(dev)->init(dev, qdev_get_info(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_info(dev)->vmsd) {
+        vmstate_register_with_alias_id(dev, -1, qdev_get_info(dev)->vmsd, 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 && qdev_get_info(dev)->reset) {
+        qdev_get_info(dev)->reset(dev);
     }
     return 0;
 }
@@ -386,17 +398,17 @@ int qdev_unplug(DeviceState *dev)
         qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
         return -1;
     }
-    assert(dev->info->unplug != NULL);
+    assert(qdev_get_info(dev)->unplug != NULL);
 
     qdev_hot_removed = true;
 
-    return dev->info->unplug(dev);
+    return qdev_get_info(dev)->unplug(dev);
 }
 
 static int qdev_reset_one(DeviceState *dev, void *opaque)
 {
-    if (dev->info->reset) {
-        dev->info->reset(dev);
+    if (qdev_get_info(dev)->reset) {
+        qdev_get_info(dev)->reset(dev);
     }
 
     return 0;
@@ -447,7 +459,7 @@ int qdev_simple_unplug_cb(DeviceState *dev)
    way is somewhat unclean, and best avoided.  */
 void qdev_init_nofail(DeviceState *dev)
 {
-    DeviceInfo *info = dev->info;
+    DeviceInfo *info = qdev_get_info(dev);
 
     if (qdev_init(dev) < 0) {
         error_report("Initialization of device %s failed", info->name);
@@ -508,15 +520,15 @@ void qdev_free(DeviceState *dev)
             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 (qdev_get_info(dev)->vmsd)
+            vmstate_unregister(dev, qdev_get_info(dev)->vmsd, dev);
+        if (qdev_get_info(dev)->exit)
+            qdev_get_info(dev)->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++) {
+    for (prop = qdev_get_info(dev)->props; prop && prop->name; prop++) {
         if (prop->info->free) {
             prop->info->free(dev, prop);
         }
@@ -708,7 +720,7 @@ static void qbus_list_bus(DeviceState *dev)
     const char *sep = " ";
 
     error_printf("child busses at \"%s\":",
-                 dev->id ? dev->id : dev->info->name);
+                 dev->id ? dev->id : qdev_get_info(dev)->name);
     QLIST_FOREACH(child, &dev->child_bus, sibling) {
         error_printf("%s\"%s\"", sep, child->name);
         sep = ", ";
@@ -723,7 +735,7 @@ static void qbus_list_dev(BusState *bus)
 
     error_printf("devices at \"%s\":", bus->name);
     QTAILQ_FOREACH(dev, &bus->children, sibling) {
-        error_printf("%s\"%s\"", sep, dev->info->name);
+        error_printf("%s\"%s\"", sep, qdev_get_info(dev)->name);
         if (dev->id)
             error_printf("/\"%s\"", dev->id);
         sep = ", ";
@@ -759,12 +771,12 @@ static DeviceState *qbus_find_dev(BusState *bus, char *elem)
         }
     }
     QTAILQ_FOREACH(dev, &bus->children, sibling) {
-        if (strcmp(dev->info->name, elem) == 0) {
+        if (strcmp(qdev_get_info(dev)->name, elem) == 0) {
             return dev;
         }
     }
     QTAILQ_FOREACH(dev, &bus->children, sibling) {
-        if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
+        if (qdev_get_info(dev)->alias && strcmp(qdev_get_info(dev)->alias, elem) == 0) {
             return dev;
         }
     }
@@ -966,7 +978,7 @@ static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
 static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
 {
     BusState *child;
-    qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
+    qdev_printf("dev: %s, id \"%s\"\n", qdev_get_info(dev)->name,
                 dev->id ? dev->id : "");
     indent += 2;
     if (dev->num_gpio_in) {
@@ -975,7 +987,7 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
     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, qdev_get_info(dev)->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);
@@ -1056,7 +1068,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", qdev_get_info(dev)->name);
         }
     }
     l += snprintf(p + l , size - l, "/");
@@ -1078,7 +1090,7 @@ char* qdev_get_fw_dev_path(DeviceState *dev)
 
 char *qdev_get_type(DeviceState *dev, Error **errp)
 {
-    return g_strdup(dev->info->name);
+    return g_strdup(qdev_get_info(dev)->name);
 }
 
 void qdev_ref(DeviceState *dev)
@@ -1288,7 +1300,7 @@ void qdev_property_add_child(DeviceState *dev, const char *name,
 {
     gchar *type;
 
-    type = g_strdup_printf("child<%s>", child->info->name);
+    type = g_strdup_printf("child<%s>", qdev_get_info(child)->name);
 
     qdev_property_add(dev, name, type, qdev_get_child_property,
                       NULL, qdev_release_child_property,
@@ -1340,7 +1352,7 @@ static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque,
         if (target) {
             gchar *target_type;
 
-            target_type = g_strdup_printf("link<%s>", target->info->name);
+            target_type = g_strdup_printf("link<%s>", qdev_get_info(target)->name);
             if (strcmp(target_type, type) == 0) {
                 *child = target;
                 qdev_ref(target);
diff --git a/hw/qdev.h b/hw/qdev.h
index 1e01a04..e13111f 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -69,9 +69,12 @@ typedef struct DeviceProperty
 
 #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)
 
 typedef struct DeviceClass {
     ObjectClass parent_class;
+    DeviceInfo *info;
 } DeviceClass;
 
 /* This structure should not be accessed directly.  We declare it here
@@ -83,7 +86,6 @@ struct DeviceState {
     enum DevState state;
     QemuOpts *opts;
     int hotplugged;
-    DeviceInfo *info;
     BusState *parent_bus;
     int num_gpio_out;
     qemu_irq *gpio_out;
@@ -389,9 +391,19 @@ 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);
 
+DeviceInfo *qdev_get_info(DeviceState *dev);
+
 static inline const char *qdev_fw_name(DeviceState *dev)
 {
-    return dev->info->fw_name ? : dev->info->alias ? : dev->info->name;
+    DeviceInfo *info = qdev_get_info(dev);
+
+    if (info->fw_name) {
+        return info->fw_name;
+    } else if (info->alias) {
+        return info->alias;
+    }
+
+    return info->name;
 }
 
 char *qdev_get_fw_dev_path(DeviceState *dev);
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 0ae9f57..16d948e 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);
+                          qdev_get_info(&dev->qdev)->name, dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
 
     s->cplus_txbuffer = NULL;
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index 82b8811..b83a893 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -752,7 +752,7 @@ 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);
+                          qdev_get_info(&dev->qdev)->name, dev->qdev.id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
     /* ??? Save/restore.  */
     return 0;
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 7a86dc8..0159413 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -75,7 +75,7 @@ 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;
+    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qdev_get_info(&dev->qdev);
     char *name;
 
     /* Device tree style name device at reg */
@@ -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;
+    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qdev_get_info(&dev->qdev);
     int vdevice_off, node_off, ret;
     char *dt_name;
 
@@ -700,7 +700,7 @@ static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr,
         return H_PARAMETER;
     }
 
-    info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+    info = (VIOsPAPRDeviceInfo *)qdev_get_info(&dev->qdev);
 
     if (mode & ~info->signal_mask) {
         return H_PARAMETER;
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index c5fb096..181dd0e 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -163,7 +163,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 (qdev_get_info(iter) != &spapr_vty.qdev) {
             continue;
         }
 
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index 016a3f2..3b80d5e 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -250,7 +250,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(qdev_get_info(&dev->qdev)->name, "usb-hub") != 0) {
             /* Create a new hub and chain it on */
             usb_create_simple(bus, "usb-hub");
         }
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index e9935ad..3b7f95d 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -1114,7 +1114,7 @@ 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);
+    CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, qdev_get_info(qdev));
     USBCCIDState *s =
         DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
 
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 2f527a8..086aa7e 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1337,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);
+                          qdev_get_info(&s->dev.qdev)->name, 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",
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 69463d2..afa3274 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1777,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 = qdev_get_info(dev)->name;
     usb_packet_init(&ohci->usb_packet);
 
     ohci->async_td = 0;
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index 0b28a30..f25adc4 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -110,7 +110,7 @@ static int virtconsole_initfn(VirtIOSerialPort *port)
 {
     VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
     VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
-                                           vcon->port.dev.info);
+                                           qdev_get_info(&vcon->port.dev));
 
     if (port->id == 0 && !info->is_console) {
         error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility.");
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 8c2f460..6c785d0 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, qdev_get_info(dev)->name, dev->id, n);
 
     qemu_format_nic_info_str(&n->nic->nc, conf->macaddr.a);
 
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 32e46e9..982ffbf 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -138,7 +138,7 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
     assert(port);
     assert(virtio_queue_ready(vq));
 
-    info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
+    info = DO_UPCAST(VirtIOSerialPortInfo, qdev, qdev_get_info(&port->dev));
 
     while (!port->throttled) {
         unsigned int i;
@@ -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);
+    info = DO_UPCAST(VirtIOSerialPortInfo, qdev, qdev_get_info(&port->dev));
 
     switch(cpkt.event) {
     case VIRTIO_CONSOLE_PORT_READY:
@@ -824,7 +824,7 @@ static int virtser_port_qdev_exit(DeviceState *qdev)
 {
     VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
     VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
-                                           port->dev.info);
+                                           qdev_get_info(&port->dev));
     VirtIOSerial *vser = port->vser;
 
     qemu_bh_delete(port->bh);
diff --git a/hw/xgmac.c b/hw/xgmac.c
index be63a7d..ccb9759 100644
--- a/hw/xgmac.c
+++ b/hw/xgmac.c
@@ -390,7 +390,7 @@ static int xgmac_enet_init(SysBusDevice *dev)
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     s->nic = qemu_new_nic(&net_xgmac_enet_info, &s->conf,
-                          dev->qdev.info->name, dev->qdev.id, s);
+                          qdev_get_info(&dev->qdev)->name, 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) |
commit 32fea4025bfb80f2dbc5c3ce415703af28d85f63
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 16 14:34:46 2011 -0600

    qdev: integrate with QEMU Object Model (v2)
    
    This is a very shallow integration.  We register a TYPE_DEVICE but only use
    QOM as basically a memory allocator.  This will make all devices show up as
    QOM objects but they will all carry the TYPE_DEVICE.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    ---
    v1 -> v2
     - update for new location of object.h

diff --git a/hw/qdev.c b/hw/qdev.c
index 5a75668..3bc9166 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -47,9 +47,17 @@ static BusState *qbus_find(const char *path);
 /* Register a new device type.  */
 void qdev_register(DeviceInfo *info)
 {
+    TypeInfo type_info = {};
+
     assert(info->size >= sizeof(DeviceState));
     assert(!info->next);
 
+    type_info.name = info->name;
+    type_info.parent = TYPE_DEVICE;
+    type_info.instance_size = info->size;
+
+    type_register_static(&type_info);
+
     info->next = device_info_list;
     device_info_list = info;
 }
@@ -93,7 +101,7 @@ static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
     Property *prop;
 
     assert(bus->info == info->bus_info);
-    dev = g_malloc0(info->size);
+    dev = DEVICE(object_new(info->name));
     dev->info = info;
     dev->parent_bus = bus;
     qdev_prop_set_defaults(dev, dev->info->props);
@@ -519,7 +527,7 @@ void qdev_free(DeviceState *dev)
     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)
@@ -1572,3 +1580,18 @@ void qdev_machine_init(void)
     qdev_get_peripheral_anon();
     qdev_get_peripheral();
 }
+
+static TypeInfo device_type_info = {
+    .name = TYPE_DEVICE,
+    .parent = TYPE_OBJECT,
+    .instance_size = sizeof(DeviceState),
+    .abstract = true,
+    .class_size = sizeof(DeviceClass),
+};
+
+static void init_qdev(void)
+{
+    type_register_static(&device_type_info);
+}
+
+device_init(init_qdev);
diff --git a/hw/qdev.h b/hw/qdev.h
index 6b58dd8..1e01a04 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;
 
@@ -66,9 +67,18 @@ typedef struct DeviceProperty
     QTAILQ_ENTRY(DeviceProperty) node;
 } DeviceProperty;
 
+#define TYPE_DEVICE "device"
+#define DEVICE(obj) OBJECT_CHECK(DeviceState, (obj), TYPE_DEVICE)
+
+typedef struct DeviceClass {
+    ObjectClass parent_class;
+} 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;
commit 2f28d2ff9dce3c404b36e90e64541a4d48daf0ca
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Sat Dec 3 17:10:08 2011 -0600

    qom: add the base Object class (v2)
    
    This class provides the main building block for QEMU Object Model and is
    extensively documented in the header file.  It is largely inspired by GObject.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    ---
    v1 -> v2
     - remove printf() in type registration
     - fix typo in comment (Paolo)
     - make Interface private
     - move object into a new directory and move header into include/qemu/
     - don't make object.h depend on qemu-common.h
     - remove Type and replace it with TypeImpl * (Paolo)
     - use hash table to store types (Paolo)
     - aggressively cache parent type (Paolo)
     - make a type_register and use it with interfaces (Paolo)
     - fix interface cast comment (Paolo)
     - add a few more functions required in later series

diff --git a/Makefile b/Makefile
index 917fb9b..d172cbf 100644
--- a/Makefile
+++ b/Makefile
@@ -114,6 +114,8 @@ QEMU_CFLAGS+=$(CURL_CFLAGS)
 
 QEMU_CFLAGS+=$(GLIB_CFLAGS)
 
+QEMU_CFLAGS += -I$(SRC_PATH)/include
+
 ui/cocoa.o: ui/cocoa.m
 
 ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
diff --git a/Makefile.hw b/Makefile.hw
index 63eb7e4..7b8d068 100644
--- a/Makefile.hw
+++ b/Makefile.hw
@@ -11,6 +11,7 @@ $(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw)
 
 QEMU_CFLAGS+=-I..
 QEMU_CFLAGS += $(GLIB_CFLAGS)
+QEMU_CFLAGS += -I$(SRC_PATH)/include
 
 include $(SRC_PATH)/Makefile.objs
 
diff --git a/Makefile.objs b/Makefile.objs
index 06a147b..b942625 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -124,6 +124,9 @@ common-obj-$(CONFIG_WIN32) += version.o
 
 common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o ui/spice-display.o spice-qemu-char.o
 
+include $(SRC_PATH)/qom/Makefile
+common-obj-y += $(addprefix qom/, $(qom-y))
+
 audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
 audio-obj-$(CONFIG_SDL) += sdlaudio.o
 audio-obj-$(CONFIG_OSS) += ossaudio.o
diff --git a/Makefile.target b/Makefile.target
index 3c85085..68481a3 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -22,6 +22,8 @@ QEMU_CFLAGS += -I.. -I$(TARGET_PATH) -DNEED_CPU_H
 
 include $(SRC_PATH)/Makefile.objs
 
+QEMU_CFLAGS+=-I$(SRC_PATH)/include
+
 ifdef CONFIG_USER_ONLY
 # user emulator name
 QEMU_PROG=qemu-$(TARGET_ARCH2)
diff --git a/configure b/configure
index 69fb239..f69e08f 100755
--- a/configure
+++ b/configure
@@ -3785,7 +3785,7 @@ DIRS="$DIRS pc-bios/spapr-rtas"
 DIRS="$DIRS roms/seabios roms/vgabios"
 DIRS="$DIRS fsdev ui"
 DIRS="$DIRS qapi qapi-generated"
-DIRS="$DIRS qga trace"
+DIRS="$DIRS qga trace qom"
 FILES="Makefile tests/tcg/Makefile qdict-test-data.txt"
 FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit"
 FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
diff --git a/include/qemu/object.h b/include/qemu/object.h
new file mode 100644
index 0000000..ba37850
--- /dev/null
+++ b/include/qemu/object.h
@@ -0,0 +1,436 @@
+/*
+ * QEMU Object Model
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_OBJECT_H
+#define QEMU_OBJECT_H
+
+#include <glib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+struct TypeImpl;
+typedef struct TypeImpl *Type;
+
+typedef struct ObjectClass ObjectClass;
+typedef struct Object Object;
+
+typedef struct TypeInfo TypeInfo;
+
+typedef struct InterfaceClass InterfaceClass;
+typedef struct InterfaceInfo InterfaceInfo;
+
+#define TYPE_OBJECT NULL
+
+/**
+ * SECTION:object.h
+ * @title:Base Object Type System
+ * @short_description: interfaces for creating new types and objects
+ *
+ * The QEMU Object Model provides a framework for registering user creatable
+ * types and instantiating objects from those types.  QOM provides the following
+ * features:
+ *
+ *  - System for dynamically registering types
+ *  - Support for single-inheritance of types
+ *  - Multiple inheritance of stateless interfaces
+ *
+ * <example>
+ *   <title>Creating a minimal type</title>
+ *   <programlisting>
+ * #include "qdev.h"
+ *
+ * #define TYPE_MY_DEVICE "my-device"
+ *
+ * typedef struct MyDevice
+ * {
+ *     DeviceState parent;
+ *
+ *     int reg0, reg1, reg2;
+ * } MyDevice;
+ *
+ * static TypeInfo my_device_info = {
+ *     .name = TYPE_MY_DEVICE,
+ *     .parent = TYPE_DEVICE,
+ *     .instance_size = sizeof(MyDevice),
+ * };
+ *
+ * static void my_device_module_init(void)
+ * {
+ *     type_register_static(&my_device_info);
+ * }
+ *
+ * device_init(my_device_module_init);
+ *   </programlisting>
+ * </example>
+ *
+ * In the above example, we create a simple type that is described by #TypeInfo.
+ * #TypeInfo describes information about the type including what it inherits
+ * from, the instance and class size, and constructor/destructor hooks.
+ *
+ * Every type has an #ObjectClass associated with it.  #ObjectClass derivatives
+ * are instantiated dynamically but there is only ever one instance for any
+ * given type.  The #ObjectClass typically holds a table of function pointers
+ * for the virtual methods implemented by this type.
+ *
+ * Using object_new(), a new #Object derivative will be instantiated.  You can
+ * cast an #Object to a subclass (or base-class) type using
+ * object_dynamic_cast().  You typically want to define a macro wrapper around
+ * object_dynamic_cast_assert() to make it easier to convert to a specific type.
+ *
+ * # Class Initialization #
+ *
+ * Before an object is initialized, the class for the object must be
+ * initialized.  There is only one class object for all instance objects
+ * that is created lazily.
+ *
+ * Classes are initialized by first initializing any parent classes (if
+ * necessary).  After the parent class object has initialized, it will be
+ * copied into the current class object and any additional storage in the
+ * class object is zero filled.
+ *
+ * The effect of this is that classes automatically inherit any virtual
+ * function pointers that the parent class has already initialized.  All
+ * other fields will be zero filled.
+ *
+ * Once all of the parent classes have been initialized, #TypeInfo::class_init
+ * is called to let the class being instantiated provide default initialize for
+ * it's virtual functions.
+ *
+ * # Interfaces #
+ *
+ * Interfaces allow a limited form of multiple inheritance.  Instances are
+ * similar to normal types except for the fact that are only defined by
+ * their classes and never carry any state.  You can dynamically cast an object
+ * to one of its #Interface types and vice versa.
+ */
+
+/**
+ * ObjectClass:
+ *
+ * The base for all classes.  The only thing that #ObjectClass contains is an
+ * integer type handle.
+ */
+struct ObjectClass
+{
+    /*< private >*/
+    Type type;
+};
+
+/**
+ * Object:
+ *
+ * The base for all objects.  The first member of this object is a pointer to
+ * a #ObjectClass.  Since C guarantees that the first member of a structure
+ * always begins at byte 0 of that structure, as long as any sub-object places
+ * its parent as the first member, we can cast directly to a #Object.
+ *
+ * As a result, #Object contains a reference to the objects type as its
+ * first member.  This allows identification of the real type of the object at
+ * run time.
+ *
+ * #Object also contains a list of #Interfaces that this object
+ * implements.
+ */
+struct Object
+{
+    /*< private >*/
+    ObjectClass *class;
+
+    GSList *interfaces;
+};
+
+/**
+ * TypeInfo:
+ * @name: The name of the type.
+ * @parent: The name of the parent type.
+ * @instance_size: The size of the object (derivative of #Object).  If
+ *   @instance_size is 0, then the size of the object will be the size of the
+ *   parent object.
+ * @instance_init: This function is called to initialize an object.  The parent
+ *   class will have already been initialized so the type is only responsible
+ *   for initializing its own members.
+ * @instance_finalize: This function is called during object destruction.  This
+ *   is called before the parent @instance_finalize function has been called.
+ *   An object should only free the members that are unique to its type in this
+ *   function.
+ * @abstract: If this field is true, then the class is considered abstract and
+ *   cannot be directly instantiated.
+ * @class_size: The size of the class object (derivative of #ObjectClass)
+ *   for this object.  If @class_size is 0, then the size of the class will be
+ *   assumed to be the size of the parent class.  This allows a type to avoid
+ *   implementing an explicit class type if they are not adding additional
+ *   virtual functions.
+ * @class_init: This function is called after all parent class initialization
+ *   has occured to allow a class to set its default virtual method pointers.  
+ *   This is also the function to use to override virtual methods from a parent
+ *   class.
+ * @class_finalize: This function is called during class destruction and is
+ *   meant to release and dynamic parameters allocated by @class_init.
+ * @class_data: Data to pass to the @class_init and @class_finalize functions.
+ *   This can be useful when building dynamic classes.
+ * @interfaces: The list of interfaces associated with this type.  This
+ *   should point to a static array that's terminated with a zero filled
+ *   element.
+ */
+struct TypeInfo
+{
+    const char *name;
+    const char *parent;
+
+    size_t instance_size;
+    void (*instance_init)(Object *obj);
+    void (*instance_finalize)(Object *obj);
+
+    bool abstract;
+    size_t class_size;
+
+    void (*class_init)(ObjectClass *klass, void *data);
+    void (*class_finalize)(ObjectClass *klass, void *data);
+    void *class_data;
+
+    InterfaceInfo *interfaces;
+};
+
+/**
+ * OBJECT:
+ * @obj: A derivative of #Object
+ *
+ * Converts an object to a #Object.  Since all objects are #Objects,
+ * this function will always succeed.
+ */
+#define OBJECT(obj) \
+    ((Object *)(obj))
+
+/**
+ * OBJECT_CHECK:
+ * @type: The C type to use for the return value.
+ * @obj: A derivative of @type to cast.
+ * @name: The QOM typename of @type
+ *
+ * A type safe version of @object_dynamic_cast_assert.  Typically each class
+ * will define a macro based on this type to perform type safe dynamic_casts to
+ * this object type.
+ *
+ * If an invalid object is passed to this function, a run time assert will be
+ * generated.
+ */
+#define OBJECT_CHECK(type, obj, name) \
+    ((type *)object_dynamic_cast_assert((Object *)(obj), (name)))
+
+/**
+ * OBJECT_CLASS_CHECK:
+ * @class: The C type to use for the return value.
+ * @obj: A derivative of @type to cast.
+ * @name: the QOM typename of @class.
+ *
+ * A type safe version of @object_check_class.  This macro is typically wrapped
+ * by each type to perform type safe casts of a class to a specific class type.
+ */
+#define OBJECT_CLASS_CHECK(class, obj, name) \
+    ((class *)object_class_dynamic_cast_assert((ObjectClass *)(obj), (name)))
+
+/**
+ * OBJECT_GET_CLASS:
+ * @class: The C type to use for the return value.
+ * @obj: The object to obtain the class for.
+ * @name: The QOM typename of @obj.
+ *
+ * This function will return a specific class for a given object.  Its generally
+ * used by each type to provide a type safe macro to get a specific class type
+ * from an object.
+ */
+#define OBJECT_GET_CLASS(class, obj, name) \
+    OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
+
+#define OBJECT_CLASS(class) \
+    ((ObjectClass *)(class))
+
+/**
+ * InterfaceClass:
+ * @parent_class: the base class
+ *
+ * The class for all interfaces.  Subclasses of this class should only add
+ * virtual methods.
+ */
+struct InterfaceClass
+{
+    ObjectClass parent_class;
+};
+
+/**
+ * InterfaceInfo:
+ * @type: The name of the interface.
+ * @interface_initfn: This method is called during class initialization and is
+ *   used to initialize an interface associated with a class.  This function
+ *   should initialize any default virtual functions for a class and/or override
+ *   virtual functions in a parent class.
+ *
+ * The information associated with an interface.
+ */
+struct InterfaceInfo
+{
+    const char *type;
+
+    void (*interface_initfn)(ObjectClass *class, void *data);
+};
+
+#define TYPE_INTERFACE "interface"
+
+/**
+ * object_new:
+ * @typename: The name of the type of the object to instantiate.
+ *
+ * This function will initialize a new object using heap allocated memory.  This
+ * function should be paired with object_delete() to free the resources
+ * associated with the object.
+ *
+ * Returns: The newly allocated and instantiated object.
+ */
+Object *object_new(const char *typename);
+
+/**
+ * object_new_with_type:
+ * @type: The type of the object to instantiate.
+ *
+ * This function will initialize a new object using heap allocated memory.  This
+ * function should be paired with object_delete() to free the resources
+ * associated with the object.
+ *
+ * Returns: The newly allocated and instantiated object.
+ */
+Object *object_new_with_type(Type type);
+
+/**
+ * object_delete:
+ * @obj: The object to free.
+ *
+ * Finalize an object and then free the memory associated with it.  This should
+ * be paired with object_new() to free the resources associated with an object.
+ */
+void object_delete(Object *obj);
+
+/**
+ * object_initialize_with_type:
+ * @obj: A pointer to the memory to be used for the object.
+ * @type: The type of the object to instantiate.
+ *
+ * This function will initialize an object.  The memory for the object should
+ * have already been allocated.
+ */
+void object_initialize_with_type(void *data, Type type);
+
+/**
+ * object_initialize:
+ * @obj: A pointer to the memory to be used for the object.
+ * @typename: The name of the type of the object to instantiate.
+ *
+ * This function will initialize an object.  The memory for the object should
+ * have already been allocated.
+ */
+void object_initialize(void *obj, const char *typename);
+
+/**
+ * object_finalize:
+ * @obj: The object to finalize.
+ *
+ * This function destroys and object without freeing the memory associated with
+ * it.
+ */
+void object_finalize(void *obj);
+
+/**
+ * object_dynamic_cast:
+ * @obj: The object to cast.
+ * @typename: The @typename to cast to.
+ *
+ * This function will determine if @obj is-a @typename.  @obj can refer to an
+ * object or an interface associated with an object.
+ *
+ * Returns: This function returns @obj on success or #NULL on failure.
+ */
+Object *object_dynamic_cast(Object *obj, const char *typename);
+
+/**
+ * @object_dynamic_cast_assert:
+ *
+ * See object_dynamic_cast() for a description of the parameters of this
+ * function.  The only difference in behavior is that this function asserts
+ * instead of returning #NULL on failure.
+ */
+Object *object_dynamic_cast_assert(Object *obj, const char *typename);
+
+/**
+ * object_get_class:
+ * @obj: A derivative of #Object
+ *
+ * Returns: The #ObjectClass of the type associated with @obj.
+ */
+ObjectClass *object_get_class(Object *obj);
+
+/**
+ * object_get_typename:
+ * @obj: A derivative of #Object.
+ *
+ * Returns: The QOM typename of @obj.
+ */
+const char *object_get_typename(Object *obj);
+
+/**
+ * type_register_static:
+ * @info: The #TypeInfo of the new type.
+ *
+ * @info and all of the strings it points to should exist for the life time
+ * that the type is registered.
+ *
+ * Returns: 0 on failure, the new #Type on success.
+ */
+Type type_register_static(const TypeInfo *info);
+
+/**
+ * type_register:
+ * @info: The #TypeInfo of the new type
+ *
+ * Unlike type_register_static(), this call does not require @info or it's
+ * string members to continue to exist after the call returns.
+ *
+ * Returns: 0 on failure, the new #Type on success.
+ */
+Type type_register(const TypeInfo *info);
+
+/**
+ * object_class_dynamic_cast_assert:
+ * @klass: The #ObjectClass to attempt to cast.
+ * @typename: The QOM typename of the class to cast to.
+ *
+ * Returns: This function always returns @klass and asserts on failure.
+ */
+ObjectClass *object_class_dynamic_cast_assert(ObjectClass *klass,
+                                              const char *typename);
+
+ObjectClass *object_class_dynamic_cast(ObjectClass *klass,
+                                       const char *typename);
+
+/**
+ * object_class_get_name:
+ * @klass: The class to obtain the QOM typename for.
+ *
+ * Returns: The QOM typename for @klass.
+ */
+const char *object_class_get_name(ObjectClass *klass);
+
+ObjectClass *object_class_by_name(const char *typename);
+
+void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
+                          void *opaque);
+
+#endif
diff --git a/qom/Makefile b/qom/Makefile
new file mode 100644
index 0000000..a3c7892
--- /dev/null
+++ b/qom/Makefile
@@ -0,0 +1 @@
+qom-y = object.o
diff --git a/qom/object.c b/qom/object.c
new file mode 100644
index 0000000..ef37e08
--- /dev/null
+++ b/qom/object.c
@@ -0,0 +1,485 @@
+/*
+ * QEMU Object Model
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/object.h"
+#include "qemu-common.h"
+
+#define MAX_INTERFACES 32
+
+typedef struct InterfaceImpl InterfaceImpl;
+typedef struct TypeImpl TypeImpl;
+
+struct InterfaceImpl
+{
+    const char *parent;
+    void (*interface_initfn)(ObjectClass *class, void *data);
+    TypeImpl *type;
+};
+
+struct TypeImpl
+{
+    const char *name;
+
+    size_t class_size;
+
+    size_t instance_size;
+
+    void (*class_init)(ObjectClass *klass, void *data);
+    void (*class_finalize)(ObjectClass *klass, void *data);
+
+    void *class_data;
+
+    void (*instance_init)(Object *obj);
+    void (*instance_finalize)(Object *obj);
+
+    bool abstract;
+
+    const char *parent;
+    TypeImpl *parent_type;
+
+    ObjectClass *class;
+
+    int num_interfaces;
+    InterfaceImpl interfaces[MAX_INTERFACES];
+};
+
+typedef struct Interface
+{
+    Object parent;
+    Object *obj;
+} Interface;
+
+#define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
+
+static GHashTable *type_table_get(void)
+{
+    static GHashTable *type_table;
+
+    if (type_table == NULL) {
+        type_table = g_hash_table_new(g_str_hash, g_str_equal);
+    }
+
+    return type_table;
+}
+
+static void type_table_add(TypeImpl *ti)
+{
+    g_hash_table_insert(type_table_get(), (void *)ti->name, ti);
+}
+
+static TypeImpl *type_table_lookup(const char *name)
+{
+    return g_hash_table_lookup(type_table_get(), name);
+}
+
+TypeImpl *type_register(const TypeInfo *info)
+{
+    TypeImpl *ti = g_malloc0(sizeof(*ti));
+
+    g_assert(info->name != NULL);
+
+    ti->name = g_strdup(info->name);
+    ti->parent = g_strdup(info->parent);
+
+    ti->class_size = info->class_size;
+    ti->instance_size = info->instance_size;
+
+    ti->class_init = info->class_init;
+    ti->class_finalize = info->class_finalize;
+    ti->class_data = info->class_data;
+
+    ti->instance_init = info->instance_init;
+    ti->instance_finalize = info->instance_finalize;
+
+    ti->abstract = info->abstract;
+
+    if (info->interfaces) {
+        int i;
+
+        for (i = 0; info->interfaces[i].type; i++) {
+            ti->interfaces[i].parent = info->interfaces[i].type;
+            ti->interfaces[i].interface_initfn = info->interfaces[i].interface_initfn;
+            ti->num_interfaces++;
+        }
+    }
+
+    type_table_add(ti);
+
+    return ti;
+}
+
+TypeImpl *type_register_static(const TypeInfo *info)
+{
+    return type_register(info);
+}
+
+static TypeImpl *type_get_by_name(const char *name)
+{
+    if (name == NULL) {
+        return NULL;
+    }
+
+    return type_table_lookup(name);
+}
+
+static TypeImpl *type_get_parent(TypeImpl *type)
+{
+    if (!type->parent_type && type->parent) {
+        type->parent_type = type_get_by_name(type->parent);
+        g_assert(type->parent_type != NULL);
+    }
+
+    return type->parent_type;
+}
+
+static bool type_has_parent(TypeImpl *type)
+{
+    return (type->parent != NULL);
+}
+
+static size_t type_class_get_size(TypeImpl *ti)
+{
+    if (ti->class_size) {
+        return ti->class_size;
+    }
+
+    if (type_has_parent(ti)) {
+        return type_class_get_size(type_get_parent(ti));
+    }
+
+    return sizeof(ObjectClass);
+}
+
+static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface)
+{
+    TypeInfo info = {
+        .instance_size = sizeof(Interface),
+        .parent = iface->parent,
+        .class_size = sizeof(InterfaceClass),
+        .class_init = iface->interface_initfn,
+        .abstract = true,
+    };
+    char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent);
+
+    info.name = name;
+    iface->type = type_register(&info);
+    g_free(name);
+}
+
+static void type_class_init(TypeImpl *ti)
+{
+    size_t class_size = sizeof(ObjectClass);
+    int i;
+
+    if (ti->class) {
+        return;
+    }
+
+    ti->class_size = type_class_get_size(ti);
+
+    ti->class = g_malloc0(ti->class_size);
+    ti->class->type = ti;
+
+    if (type_has_parent(ti)) {
+        TypeImpl *parent = type_get_parent(ti);
+
+        type_class_init(parent);
+
+        class_size = parent->class_size;
+        g_assert(parent->class_size <= ti->class_size);
+
+        memcpy((void *)ti->class + sizeof(ObjectClass),
+               (void *)parent->class + sizeof(ObjectClass),
+               parent->class_size - sizeof(ObjectClass));
+    }
+
+    memset((void *)ti->class + class_size, 0, ti->class_size - class_size);
+
+    for (i = 0; i < ti->num_interfaces; i++) {
+        type_class_interface_init(ti, &ti->interfaces[i]);
+    }
+
+    if (ti->class_init) {
+        ti->class_init(ti->class, ti->class_data);
+    }
+}
+
+static void object_interface_init(Object *obj, InterfaceImpl *iface)
+{
+    TypeImpl *ti = iface->type;
+    Interface *iface_obj;
+
+    iface_obj = INTERFACE(object_new(ti->name));
+    iface_obj->obj = obj;
+
+    obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj);
+}
+
+static void object_init_with_type(Object *obj, TypeImpl *ti)
+{
+    int i;
+
+    if (type_has_parent(ti)) {
+        object_init_with_type(obj, type_get_parent(ti));
+    }
+
+    for (i = 0; i < ti->num_interfaces; i++) {
+        object_interface_init(obj, &ti->interfaces[i]);
+    }
+
+    if (ti->instance_init) {
+        ti->instance_init(obj);
+    }
+}
+
+void object_initialize_with_type(void *data, TypeImpl *type)
+{
+    Object *obj = data;
+
+    g_assert(type != NULL);
+    g_assert(type->instance_size >= sizeof(ObjectClass));
+
+    type_class_init(type);
+    g_assert(type->abstract == false);
+
+    memset(obj, 0, type->instance_size);
+    obj->class = type->class;
+    object_init_with_type(obj, type);
+}
+
+void object_initialize(void *data, const char *typename)
+{
+    TypeImpl *type = type_get_by_name(typename);
+
+    object_initialize_with_type(data, type);
+}
+
+static void object_deinit(Object *obj, TypeImpl *type)
+{
+    if (type->instance_finalize) {
+        type->instance_finalize(obj);
+    }
+
+    while (obj->interfaces) {
+        Interface *iface_obj = obj->interfaces->data;
+        obj->interfaces = g_slist_delete_link(obj->interfaces, obj->interfaces);
+        object_delete(OBJECT(iface_obj));
+    }
+
+    if (type_has_parent(type)) {
+        object_deinit(obj, type_get_parent(type));
+    }
+}
+
+void object_finalize(void *data)
+{
+    Object *obj = data;
+    TypeImpl *ti = obj->class->type;
+
+    object_deinit(obj, ti);
+}
+
+Object *object_new_with_type(Type type)
+{
+    Object *obj;
+
+    g_assert(type != NULL);
+
+    obj = g_malloc(type->instance_size);
+    object_initialize_with_type(obj, type);
+
+    return obj;
+}
+
+Object *object_new(const char *typename)
+{
+    TypeImpl *ti = type_get_by_name(typename);
+
+    return object_new_with_type(ti);
+}
+
+void object_delete(Object *obj)
+{
+    object_finalize(obj);
+    g_free(obj);
+}
+
+static bool object_is_type(Object *obj, const char *typename)
+{
+    TypeImpl *target_type = type_get_by_name(typename);
+    TypeImpl *type = obj->class->type;
+    GSList *i;
+
+    /* Check if typename is a direct ancestor of type */
+    while (type) {
+        if (type == target_type) {
+            return true;
+        }
+
+        type = type_get_parent(type);
+    }
+
+    /* Check if obj has an interface of typename */
+    for (i = obj->interfaces; i; i = i->next) {
+        Interface *iface = i->data;
+
+        if (object_is_type(OBJECT(iface), typename)) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+Object *object_dynamic_cast(Object *obj, const char *typename)
+{
+    GSList *i;
+
+    /* Check if typename is a direct ancestor */
+    if (object_is_type(obj, typename)) {
+        return obj;
+    }
+
+    /* Check if obj has an interface of typename */
+    for (i = obj->interfaces; i; i = i->next) {
+        Interface *iface = i->data;
+
+        if (object_is_type(OBJECT(iface), typename)) {
+            return OBJECT(iface);
+        }
+    }
+
+    /* Check if obj is an interface and its containing object is a direct
+     * ancestor of typename */
+    if (object_is_type(obj, TYPE_INTERFACE)) {
+        Interface *iface = INTERFACE(obj);
+
+        if (object_is_type(iface->obj, typename)) {
+            return iface->obj;
+        }
+    }
+
+    return NULL;
+}
+
+
+static void register_interface(void)
+{
+    static TypeInfo interface_info = {
+        .name = TYPE_INTERFACE,
+        .instance_size = sizeof(Interface),
+        .abstract = true,
+    };
+
+    type_register_static(&interface_info);
+}
+
+device_init(register_interface);
+
+Object *object_dynamic_cast_assert(Object *obj, const char *typename)
+{
+    Object *inst;
+
+    inst = object_dynamic_cast(obj, typename);
+
+    if (!inst) {
+        fprintf(stderr, "Object %p is not an instance of type %s\n",
+                obj, typename);
+        abort();
+    }
+
+    return inst;
+}
+
+ObjectClass *object_class_dynamic_cast(ObjectClass *class,
+                                       const char *typename)
+{
+    TypeImpl *target_type = type_get_by_name(typename);
+    TypeImpl *type = class->type;
+
+    while (type) {
+        if (type == target_type) {
+            return class;
+        }
+
+        type = type_get_parent(type);
+    }
+
+    return NULL;
+}
+
+ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
+                                              const char *typename)
+{
+    ObjectClass *ret = object_class_dynamic_cast(class, typename);
+
+    if (!ret) {
+        fprintf(stderr, "Object %p is not an instance of type %s\n",
+                class, typename);
+        abort();
+    }
+
+    return ret;
+}
+
+const char *object_get_typename(Object *obj)
+{
+    return obj->class->type->name;
+}
+
+ObjectClass *object_get_class(Object *obj)
+{
+    return obj->class;
+}
+
+const char *object_class_get_name(ObjectClass *klass)
+{
+    return klass->type->name;
+}
+
+ObjectClass *object_class_by_name(const char *typename)
+{
+    TypeImpl *type = type_get_by_name(typename);
+
+    if (!type) {
+        return NULL;
+    }
+
+    type_class_init(type);
+
+    return type->class;
+}
+
+typedef struct OCFData
+{
+    void (*fn)(ObjectClass *klass, void *opaque);
+    void *opaque;
+} OCFData;
+
+static void object_class_foreach_tramp(gpointer key, gpointer value,
+                                       gpointer opaque)
+{
+    OCFData *data = opaque;
+    TypeImpl *type = value;
+
+    type_class_init(type);
+
+    data->fn(value, type->class);
+}
+
+void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
+                          void *opaque)
+{
+    OCFData data = { fn, opaque };
+
+    g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
+}
commit 6fc4925bf612e00c149d23ef1761dedc8aae1a46
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Sun Dec 4 11:40:58 2011 -0600

    pci: call reset unconditionally
    
    Because now all PCI devices are converted to qdev.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/pci.c b/hw/pci.c
index 54400ac..ab3b53d 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -159,11 +159,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);
commit 8a5faa1d3eeed16cce6f20ce4b5bda453f0469e2
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Dec 21 16:18:02 2011 -0600

    openpic: remove dead code to make a PCI device version
    
    bus is always NULL so the code in this if clause is dead (and therefore
    untested).
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/openpic.c b/hw/openpic.c
index 22fc275..280b7a9 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 715f084..8556030 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/ppc_newworld.c b/hw/ppc_newworld.c
index a746c9c..506187b 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());
commit d8c51b052b6a9fe47477c4756ac69a070b176343
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Dec 21 16:14:09 2011 -0600

    macio: convert to qdev
    
    This is a "shallow", half hearted, and untested conversion.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/macio.c b/hw/macio.c
index cc6ae40..357e0ea 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,27 @@ 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 PCIDeviceInfo macio_info = {
+    .qdev.name = "macio",
+    .qdev.size = sizeof(MacIOState),
+    .init = macio_initfn,
+    .vendor_id = PCI_VENDOR_ID_APPLE,
+    .class_id = PCI_CLASS_OTHERS << 8,
+};
+
+static void macio_register(void)
+{
+    pci_qdev_register(&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 +103,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 +125,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);
commit 31841e463fc069f3370f85060fbe450b3ff664b4
Merge: 21fe5bc... 2488514...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Jan 27 09:00:03 2012 -0600

    Merge remote-tracking branch 'pmaydell/arm-devs.for-upstream' into staging
    
    * pmaydell/arm-devs.for-upstream:
      arm: SoC model for Calxeda Highbank
      arm_boot: support board IDs more than 16 bits wide
      arm: add secondary cpu boot callbacks to arm_boot.c
      ahci: add support for non-PCI based controllers
      Add xgmac ethernet model

commit 21fe5bc678b16d748db385fb1be95caa96b00eee
Merge: 96bab41... e2f0c49...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Jan 27 08:58:52 2012 -0600

    Merge remote-tracking branch 'kwolf/for-anthony' into staging
    
    * kwolf/for-anthony: (22 commits)
      scsi: Guard against buflen exceeding req->cmd.xfer in scsi_disk_emulate_command
      qcow: Use bdrv functions to replace file operation
      qcow: Return real error code in qcow_open
      block/vdi: Zero unused parts when allocating a new block (fix #919242)
      virtio-blk: add virtio_blk_handle_read trace event
      docs: describe live block operations
      block: add support for partial streaming
      add QERR_BASE_NOT_FOUND
      block: add bdrv_find_backing_image
      blockdev: make image streaming safe across hotplug
      qmp: add query-block-jobs
      qmp: add block_job_cancel command
      qmp: add block_job_set_speed command
      qmp: add block_stream command
      block: rate-limit streaming operations
      block: add image streaming block job
      block: add BlockJob interface for long-running operations
      block: make copy-on-read a per-request flag
      block: check bdrv_in_use() before blockdev operations
      coroutine: add co_sleep_ns() coroutine sleep function
      ...

commit 96bab41df61b532bb6954a38527ad8403859a6c9
Author: Laszlo Ersek <lersek at redhat.com>
Date:   Tue Jan 24 21:13:28 2012 +0100

    qemu-io: end aio help text sentences with periods
    
    Signed-off-by: Laszlo Ersek <lersek at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/qemu-io.c b/qemu-io.c
index ffa62fb..938b20c 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1118,7 +1118,7 @@ static void aio_read_help(void)
 " Reads a segment of the currently open file, optionally dumping it to the\n"
 " standard output stream (with -v option) for subsequent inspection.\n"
 " The read is performed asynchronously and the aio_flush command must be\n"
-" used to ensure all outstanding aio requests have been completed\n"
+" used to ensure all outstanding aio requests have been completed.\n"
 " -C, -- report statistics in a machine parsable format\n"
 " -P, -- use a pattern to verify read data\n"
 " -v, -- dump buffer to standard output\n"
@@ -1214,7 +1214,7 @@ static void aio_write_help(void)
 " Writes into a segment of the currently open file, using a buffer\n"
 " filled with a set pattern (0xcdcdcdcd).\n"
 " The write is performed asynchronously and the aio_flush command must be\n"
-" used to ensure all outstanding aio requests have been completed\n"
+" used to ensure all outstanding aio requests have been completed.\n"
 " -P, -- use different pattern to fill file\n"
 " -C, -- report statistics in a machine parsable format\n"
 " -q, -- quiet mode, do not show I/O statistics\n"
commit 8c84cf11660322489f839bc29db79bad31b4ecde
Author: Sergei Trofimovich <slyfox at gentoo.org>
Date:   Tue Jan 24 20:42:40 2012 +0300

    ./configure: export xfs config via --{enable, disable}-xfsctl
    
    Signed-off-by: Sergei Trofimovich <slyfox at gentoo.org>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/configure b/configure
index 9d5175b..69fb239 100755
--- a/configure
+++ b/configure
@@ -766,6 +766,10 @@ for opt do
   ;;
   --enable-rbd) rbd="yes"
   ;;
+  --disable-xfsctl) xfs="no"
+  ;;
+  --enable-xfsctl) xfs="yes"
+  ;;
   --disable-smartcard) smartcard="no"
   ;;
   --enable-smartcard) smartcard="yes"
commit 9f2a8d7ae8a74726024cc6b820e58d841199d37b
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Jan 24 13:47:56 2012 +0100

    pcnet: Preserve link state across device reset
    
    A device reset does not affect the link state, only set_link does.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/pcnet.c b/hw/pcnet.c
index 306dc6e..6aa48e0 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;
@@ -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;
 }
commit b1927cf1ae6161942dcca115f20a3e6e7b0a6cc3
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Jan 24 13:47:46 2012 +0100

    e1000: Preserve link state across device reset
    
    A device reset does not affect the link state, only set_link does.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/e1000.c b/hw/e1000.c
index 86c5416..76e736f 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -1133,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 = {
commit c455d17c09f797055ec52afc25e8735c72d00ca0
Author: Jan Kiszka <jan.kiszka at web.de>
Date:   Sat Jan 21 14:43:07 2012 +0100

    qdev-property: Make bit property parsing stricter
    
    By using strncasecmp, we allow for arbitrary characters after the
    "on"/"off" string. Fix this by switching to strcasecmp.
    
    Reviewed-by: Andreas Färber <afaerber at suse.de>
    Reviewed-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 02f0dae..ea3b2df 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;
commit 36945d95d249eda5536bf1683f0bee1a358c7642
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Jan 20 12:05:22 2012 +0100

    remove #if 0 code for timers
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/qemu-timer.c b/qemu-timer.c
index cd026c6..a22f27e 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -494,35 +494,6 @@ static void host_alarm_handler(int host_signum)
     if (!t)
 	return;
 
-#if 0
-#define DISP_FREQ 1000
-    {
-        static int64_t delta_min = INT64_MAX;
-        static int64_t delta_max, delta_cum, last_clock, delta, ti;
-        static int count;
-        ti = qemu_get_clock_ns(vm_clock);
-        if (last_clock != 0) {
-            delta = ti - last_clock;
-            if (delta < delta_min)
-                delta_min = delta;
-            if (delta > delta_max)
-                delta_max = delta;
-            delta_cum += delta;
-            if (++count == DISP_FREQ) {
-                printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n",
-                       muldiv64(delta_min, 1000000, get_ticks_per_sec()),
-                       muldiv64(delta_max, 1000000, get_ticks_per_sec()),
-                       muldiv64(delta_cum, 1000000 / DISP_FREQ, get_ticks_per_sec()),
-                       (double)get_ticks_per_sec() / ((double)delta_cum / DISP_FREQ));
-                count = 0;
-                delta_min = INT64_MAX;
-                delta_max = 0;
-                delta_cum = 0;
-            }
-        }
-        last_clock = ti;
-    }
-#endif
     if (alarm_has_dynticks(t) ||
         qemu_next_alarm_deadline () <= 0) {
         t->expired = alarm_has_dynticks(t);
commit e2f0c49ffae8d3a00272c3cbc68850cc5aafbffa
Author: Thomas Higdon <thigdon at akamai.com>
Date:   Tue Jan 24 12:19:44 2012 -0500

    scsi: Guard against buflen exceeding req->cmd.xfer in scsi_disk_emulate_command
    
    Limit the return value (corresponding to the length of the buffer to be
    DMAed back to the intiator) to the value in req->cmd.xfer, which is the
    amount of data that the initiator expects. Eliminate now-duplicate code
    that does this guarding in the functions for individual commands.
    
    Without this, the SCRIPTS code in the emulated LSI device eventually
    raises a DMA interrupt for a data overrun when an INQUIRY command whose
    buflen exceeds req->cmd.xfer is processed. It's the responsibility of
    the client to provide a request buffer and allocation length that are
    large enough for the result of the command.
    
    Signed-off-by: Thomas Higdon <thigdon at akamai.com>
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 5d8bf53..11cfe73 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:
commit 2b16c9ffb2432f2d0f63647df6735a67b0333a51
Author: Li Zhi Hui <zhihuili at linux.vnet.ibm.com>
Date:   Mon Nov 21 15:40:39 2011 +0800

    qcow: Use bdrv functions to replace file operation
    
    Since common file operation functions lack of error detection and use
    much more I/O syscalls, so change them to bdrv series functions and
    reduce I/O request.
    
    Signed-off-by: Li Zhi Hui <zhihuili at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow.c b/block/qcow.c
index e0d0b88..b1cfe1f 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -644,13 +644,14 @@ static void qcow_close(BlockDriverState *bs)
 
 static int qcow_create(const char *filename, QEMUOptionParameter *options)
 {
-    int fd, header_size, backing_filename_len, l1_size, i, shift;
+    int header_size, backing_filename_len, l1_size, shift, i;
     QCowHeader header;
-    uint64_t tmp;
+    uint8_t *tmp;
     int64_t total_size = 0;
     const char *backing_file = NULL;
     int flags = 0;
     int ret;
+    BlockDriverState *qcow_bs;
 
     /* Read out options */
     while (options && options->name) {
@@ -664,9 +665,21 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
         options++;
     }
 
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
-    if (fd < 0)
-        return -errno;
+    ret = bdrv_create_file(filename, options);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = bdrv_file_open(&qcow_bs, filename, BDRV_O_RDWR);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = bdrv_truncate(qcow_bs, 0);
+    if (ret < 0) {
+        goto exit;
+    }
+
     memset(&header, 0, sizeof(header));
     header.magic = cpu_to_be32(QCOW_MAGIC);
     header.version = cpu_to_be32(QCOW_VERSION);
@@ -702,33 +715,34 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
     }
 
     /* write all the data */
-    ret = qemu_write_full(fd, &header, sizeof(header));
+    ret = bdrv_pwrite(qcow_bs, 0, &header, sizeof(header));
     if (ret != sizeof(header)) {
-        ret = -errno;
         goto exit;
     }
 
     if (backing_file) {
-        ret = qemu_write_full(fd, backing_file, backing_filename_len);
+        ret = bdrv_pwrite(qcow_bs, sizeof(header),
+            backing_file, backing_filename_len);
         if (ret != backing_filename_len) {
-            ret = -errno;
             goto exit;
         }
-
     }
-    lseek(fd, header_size, SEEK_SET);
-    tmp = 0;
-    for(i = 0;i < l1_size; i++) {
-        ret = qemu_write_full(fd, &tmp, sizeof(tmp));
-        if (ret != sizeof(tmp)) {
-            ret = -errno;
+
+    tmp = g_malloc0(BDRV_SECTOR_SIZE);
+    for (i = 0; i < ((sizeof(uint64_t)*l1_size + BDRV_SECTOR_SIZE - 1)/
+        BDRV_SECTOR_SIZE); i++) {
+        ret = bdrv_pwrite(qcow_bs, header_size +
+            BDRV_SECTOR_SIZE*i, tmp, BDRV_SECTOR_SIZE);
+        if (ret != BDRV_SECTOR_SIZE) {
+            g_free(tmp);
             goto exit;
         }
     }
 
+    g_free(tmp);
     ret = 0;
 exit:
-    close(fd);
+    bdrv_delete(qcow_bs);
     return ret;
 }
 
commit 84b0ec020f0189b2c73437919df21c87be74b91f
Author: Li Zhi Hui <zhihuili at linux.vnet.ibm.com>
Date:   Thu Dec 15 18:14:00 2011 +0800

    qcow: Return real error code in qcow_open
    
    Signed-off-by: Li Zhi Hui <zhihuili at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow.c b/block/qcow.c
index b16955d..e0d0b88 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -95,11 +95,13 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
 static int qcow_open(BlockDriverState *bs, int flags)
 {
     BDRVQcowState *s = bs->opaque;
-    int len, i, shift;
+    int len, i, shift, ret;
     QCowHeader header;
 
-    if (bdrv_pread(bs->file, 0, &header, sizeof(header)) != sizeof(header))
+    ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
+    if (ret < 0) {
         goto fail;
+    }
     be32_to_cpus(&header.magic);
     be32_to_cpus(&header.version);
     be64_to_cpus(&header.backing_file_offset);
@@ -109,15 +111,31 @@ static int qcow_open(BlockDriverState *bs, int flags)
     be32_to_cpus(&header.crypt_method);
     be64_to_cpus(&header.l1_table_offset);
 
-    if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
+    if (header.magic != QCOW_MAGIC) {
+        ret = -EINVAL;
         goto fail;
-    if (header.size <= 1 || header.cluster_bits < 9)
+    }
+    if (header.version != QCOW_VERSION) {
+        char version[64];
+        snprintf(version, sizeof(version), "QCOW version %d", header.version);
+        qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
+            bs->device_name, "qcow", version);
+        ret = -ENOTSUP;
         goto fail;
-    if (header.crypt_method > QCOW_CRYPT_AES)
+    }
+
+    if (header.size <= 1 || header.cluster_bits < 9) {
+        ret = -EINVAL;
         goto fail;
+    }
+    if (header.crypt_method > QCOW_CRYPT_AES) {
+        ret = -EINVAL;
+        goto fail;
+    }
     s->crypt_method_header = header.crypt_method;
-    if (s->crypt_method_header)
+    if (s->crypt_method_header) {
         bs->encrypted = 1;
+    }
     s->cluster_bits = header.cluster_bits;
     s->cluster_size = 1 << s->cluster_bits;
     s->cluster_sectors = 1 << (s->cluster_bits - 9);
@@ -132,33 +150,33 @@ static int qcow_open(BlockDriverState *bs, int flags)
 
     s->l1_table_offset = header.l1_table_offset;
     s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
-    if (!s->l1_table)
-        goto fail;
-    if (bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
-        s->l1_size * sizeof(uint64_t))
+
+    ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
+               s->l1_size * sizeof(uint64_t));
+    if (ret < 0) {
         goto fail;
+    }
+
     for(i = 0;i < s->l1_size; i++) {
         be64_to_cpus(&s->l1_table[i]);
     }
     /* alloc L2 cache */
     s->l2_cache = g_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
-    if (!s->l2_cache)
-        goto fail;
     s->cluster_cache = g_malloc(s->cluster_size);
-    if (!s->cluster_cache)
-        goto fail;
     s->cluster_data = g_malloc(s->cluster_size);
-    if (!s->cluster_data)
-        goto fail;
     s->cluster_cache_offset = -1;
 
     /* read the backing file name */
     if (header.backing_file_offset != 0) {
         len = header.backing_file_size;
-        if (len > 1023)
+        if (len > 1023) {
             len = 1023;
-        if (bdrv_pread(bs->file, header.backing_file_offset, bs->backing_file, len) != len)
+        }
+        ret = bdrv_pread(bs->file, header.backing_file_offset,
+                   bs->backing_file, len);
+        if (ret < 0) {
             goto fail;
+        }
         bs->backing_file[len] = '\0';
     }
 
@@ -176,7 +194,7 @@ static int qcow_open(BlockDriverState *bs, int flags)
     g_free(s->l2_cache);
     g_free(s->cluster_cache);
     g_free(s->cluster_data);
-    return -1;
+    return ret;
 }
 
 static int qcow_set_key(BlockDriverState *bs, const char *key)
commit 641543b76b82a8b361482b727e08de0c8ec093b0
Author: Stefan Weil <sw at weilnetz.de>
Date:   Sat Jan 21 13:54:24 2012 +0100

    block/vdi: Zero unused parts when allocating a new block (fix #919242)
    
    The new block was filled with zero when it was allocated by g_malloc0,
    but when it was reused later and only partially used, data from the
    previously allocated block were still present and written to the new
    block.
    
    This caused the problems reported by bug #919242
    (https://bugs.launchpad.net/qemu/+bug/919242).
    
    Now the unused parts of the new block which are before and after the data
    are always filled with zero, so it is no longer necessary to zero the whole
    block with g_malloc0.
    
    I also updated the copyright comment.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vdi.c b/block/vdi.c
index 31cdfab..6a0011f 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -1,7 +1,7 @@
 /*
  * Block driver for the Virtual Disk Image (VDI) format
  *
- * Copyright (c) 2009 Stefan Weil
+ * Copyright (c) 2009, 2012 Stefan Weil
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -756,15 +756,19 @@ static void vdi_aio_write_cb(void *opaque, int ret)
                  (uint64_t)bmap_entry * s->block_sectors;
         block = acb->block_buffer;
         if (block == NULL) {
-            block = g_malloc0(s->block_size);
+            block = g_malloc(s->block_size);
             acb->block_buffer = block;
             acb->bmap_first = block_index;
             assert(!acb->header_modified);
             acb->header_modified = 1;
         }
         acb->bmap_last = block_index;
+        /* Copy data to be written to new block and zero unused parts. */
+        memset(block, 0, sector_in_block * SECTOR_SIZE);
         memcpy(block + sector_in_block * SECTOR_SIZE,
                acb->buf, n_sectors * SECTOR_SIZE);
+        memset(block + (sector_in_block + n_sectors) * SECTOR_SIZE, 0,
+               (s->block_sectors - n_sectors - sector_in_block) * SECTOR_SIZE);
         acb->hd_iov.iov_base = (void *)block;
         acb->hd_iov.iov_len = s->block_size;
         qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
commit 81b6b9faef111f4493addc2ed19903feace332bf
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Thu Dec 22 13:17:02 2011 +0000

    virtio-blk: add virtio_blk_handle_read trace event
    
    There already exists a virtio_blk_handle_write trace event as well as
    completion events.  Add the virtio_blk_handle_read event so it's easy to
    trace virtio-blk requests for both read and write operations.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 5b416c3..a5a4396 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/trace-events b/trace-events
index ad77e0a..75f6e17 100644
--- a/trace-events
+++ b/trace-events
@@ -83,6 +83,7 @@ qmp_block_stream(void *bs, void *job) "bs %p job %p"
 virtio_blk_req_complete(void *req, int status) "req %p status %d"
 virtio_blk_rw_complete(void *req, int ret) "req %p ret %d"
 virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
+virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
 
 # posix-aio-compat.c
 paio_submit(void *acb, void *opaque, int64_t sector_num, int nb_sectors, int type) "acb %p opaque %p sector_num %"PRId64" nb_sectors %d type %d"
commit 094f1ba10ab341b8d1306e863698a07b2afa6b09
Author: Marcelo Tosatti <mtosatti at redhat.com>
Date:   Wed Jan 18 14:40:54 2012 +0000

    docs: describe live block operations
    
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/docs/live-block-ops.txt b/docs/live-block-ops.txt
new file mode 100644
index 0000000..a257087
--- /dev/null
+++ b/docs/live-block-ops.txt
@@ -0,0 +1,58 @@
+LIVE BLOCK OPERATIONS
+=====================
+
+High level description of live block operations. Note these are not
+supported for use with the raw format at the moment.
+
+Snapshot live merge
+===================
+
+Given a snapshot chain, described in this document in the following
+format:
+
+[A] -> [B] -> [C] -> [D]
+
+Where the rightmost object ([D] in the example) described is the current
+image which the guest OS has write access to. To the left of it is its base
+image, and so on accordingly until the leftmost image, which has no
+base.
+
+The snapshot live merge operation transforms such a chain into a
+smaller one with fewer elements, such as this transformation relative
+to the first example:
+
+[A] -> [D]
+
+Currently only forward merge with target being the active image is
+supported, that is, data copy is performed in the right direction with
+destination being the rightmost image.
+
+The operation is implemented in QEMU through image streaming facilities.
+
+The basic idea is to execute 'block_stream virtio0' while the guest is
+running. Progress can be monitored using 'info block-jobs'. When the
+streaming operation completes it raises a QMP event. 'block_stream'
+copies data from the backing file(s) into the active image. When finished,
+it adjusts the backing file pointer.
+
+The 'base' parameter specifies an image which data need not be streamed from.
+This image will be used as the backing file for the active image when the
+operation is finished.
+
+In the example above, the command would be:
+
+(qemu) block_stream virtio0 A
+
+
+Live block copy
+===============
+
+To copy an in use image to another destination in the filesystem, one
+should create a live snapshot in the desired destination, then stream
+into that image. Example:
+
+(qemu) snapshot_blkdev ide0-hd0 /new-path/disk.img qcow2
+
+(qemu) block_stream ide0-hd0
+
+
commit c8c3080f4a6fbbf3c9c5d6efd1b49e7ca6479d1e
Author: Marcelo Tosatti <mtosatti at redhat.com>
Date:   Wed Jan 18 14:40:53 2012 +0000

    block: add support for partial streaming
    
    Add support for streaming data from an intermediate section of the
    image chain (see patch and documentation for details).
    
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/stream.c b/block/stream.c
index b54b0b7..d1b3986 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -57,6 +57,7 @@ typedef struct StreamBlockJob {
     BlockJob common;
     RateLimit limit;
     BlockDriverState *base;
+    char backing_file_id[1024];
 } StreamBlockJob;
 
 static int coroutine_fn stream_populate(BlockDriverState *bs,
@@ -75,10 +76,76 @@ static int coroutine_fn stream_populate(BlockDriverState *bs,
     return bdrv_co_copy_on_readv(bs, sector_num, nb_sectors, &qiov);
 }
 
+/*
+ * Given an image chain: [BASE] -> [INTER1] -> [INTER2] -> [TOP]
+ *
+ * Return true if the given sector is allocated in top.
+ * Return false if the given sector is allocated in intermediate images.
+ * Return true otherwise.
+ *
+ * 'pnum' is set to the number of sectors (including and immediately following
+ *  the specified sector) that are known to be in the same
+ *  allocated/unallocated state.
+ *
+ */
+static int coroutine_fn is_allocated_base(BlockDriverState *top,
+                                          BlockDriverState *base,
+                                          int64_t sector_num,
+                                          int nb_sectors, int *pnum)
+{
+    BlockDriverState *intermediate;
+    int ret, n;
+
+    ret = bdrv_co_is_allocated(top, sector_num, nb_sectors, &n);
+    if (ret) {
+        *pnum = n;
+        return ret;
+    }
+
+    /*
+     * Is the unallocated chunk [sector_num, n] also
+     * unallocated between base and top?
+     */
+    intermediate = top->backing_hd;
+
+    while (intermediate) {
+        int pnum_inter;
+
+        /* reached base */
+        if (intermediate == base) {
+            *pnum = n;
+            return 1;
+        }
+        ret = bdrv_co_is_allocated(intermediate, sector_num, nb_sectors,
+                                   &pnum_inter);
+        if (ret < 0) {
+            return ret;
+        } else if (ret) {
+            *pnum = pnum_inter;
+            return 0;
+        }
+
+        /*
+         * [sector_num, nb_sectors] is unallocated on top but intermediate
+         * might have
+         *
+         * [sector_num+x, nr_sectors] allocated.
+         */
+        if (n > pnum_inter) {
+            n = pnum_inter;
+        }
+
+        intermediate = intermediate->backing_hd;
+    }
+
+    return 1;
+}
+
 static void coroutine_fn stream_run(void *opaque)
 {
     StreamBlockJob *s = opaque;
     BlockDriverState *bs = s->common.bs;
+    BlockDriverState *base = s->base;
     int64_t sector_num, end;
     int ret = 0;
     int n;
@@ -108,8 +175,15 @@ retry:
             break;
         }
 
-        ret = bdrv_co_is_allocated(bs, sector_num,
-                                   STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n);
+
+        if (base) {
+            ret = is_allocated_base(bs, base, sector_num,
+                                    STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n);
+        } else {
+            ret = bdrv_co_is_allocated(bs, sector_num,
+                                       STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE,
+                                       &n);
+        }
         trace_stream_one_iteration(s, sector_num, n, ret);
         if (ret == 0) {
             if (s->common.speed) {
@@ -126,6 +200,7 @@ retry:
         if (ret < 0) {
             break;
         }
+        ret = 0;
 
         /* Publish progress */
         s->common.offset += n * BDRV_SECTOR_SIZE;
@@ -141,7 +216,11 @@ retry:
     }
 
     if (sector_num == end && ret == 0) {
-        ret = bdrv_change_backing_file(bs, NULL, NULL);
+        const char *base_id = NULL;
+        if (base) {
+            base_id = s->backing_file_id;
+        }
+        ret = bdrv_change_backing_file(bs, base_id, NULL);
     }
 
     qemu_vfree(buf);
@@ -167,7 +246,8 @@ static BlockJobType stream_job_type = {
 };
 
 int stream_start(BlockDriverState *bs, BlockDriverState *base,
-                 BlockDriverCompletionFunc *cb, void *opaque)
+                 const char *base_id, BlockDriverCompletionFunc *cb,
+                 void *opaque)
 {
     StreamBlockJob *s;
     Coroutine *co;
@@ -178,6 +258,9 @@ int stream_start(BlockDriverState *bs, BlockDriverState *base,
     }
 
     s->base = base;
+    if (base_id) {
+        pstrcpy(s->backing_file_id, sizeof(s->backing_file_id), base_id);
+    }
 
     co = qemu_coroutine_create(stream_run);
     trace_stream_start(bs, base, s, co, opaque);
diff --git a/block_int.h b/block_int.h
index 4f63870..7be2988 100644
--- a/block_int.h
+++ b/block_int.h
@@ -328,6 +328,7 @@ void block_job_cancel(BlockJob *job);
 bool block_job_is_cancelled(BlockJob *job);
 
 int stream_start(BlockDriverState *bs, BlockDriverState *base,
-                 BlockDriverCompletionFunc *cb, void *opaque);
+                 const char *base_id, BlockDriverCompletionFunc *cb,
+                 void *opaque);
 
 #endif /* BLOCK_INT_H */
diff --git a/blockdev.c b/blockdev.c
index 2fa0151..7e4c548 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -973,6 +973,7 @@ void qmp_block_stream(const char *device, bool has_base,
                       const char *base, Error **errp)
 {
     BlockDriverState *bs;
+    BlockDriverState *base_bs = NULL;
     int ret;
 
     bs = bdrv_find(device);
@@ -981,13 +982,15 @@ void qmp_block_stream(const char *device, bool has_base,
         return;
     }
 
-    /* Base device not supported */
     if (base) {
-        error_set(errp, QERR_NOT_SUPPORTED);
-        return;
+        base_bs = bdrv_find_backing_image(bs, base);
+        if (base_bs == NULL) {
+            error_set(errp, QERR_BASE_NOT_FOUND, base);
+            return;
+        }
     }
 
-    ret = stream_start(bs, NULL, block_stream_cb, bs);
+    ret = stream_start(bs, base_bs, base, block_stream_cb, bs);
     if (ret < 0) {
         switch (ret) {
         case -EBUSY:
commit 019b8cbf76fc3126d300c401acca3102c69e7876
Author: Marcelo Tosatti <mtosatti at redhat.com>
Date:   Wed Jan 18 14:40:52 2012 +0000

    add QERR_BASE_NOT_FOUND
    
    This qerror will be raised when a given streaming base (backing file)
    cannot be found.
    
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Acked-by: Luiz Capitulino <lcapitulino at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qapi-schema.json b/qapi-schema.json
index 3f72c2c..80debe6 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1493,6 +1493,7 @@
 #          If streaming is already active on this device, DeviceInUse
 #          If @device does not exist, DeviceNotFound
 #          If image streaming is not supported by this device, NotSupported
+#          If @base does not exist, BaseNotFound
 #
 # Since: 1.1
 ##
diff --git a/qerror.c b/qerror.c
index 2c60e10..637eca7 100644
--- a/qerror.c
+++ b/qerror.c
@@ -52,6 +52,10 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "Device '%(device)' can't go on a %(bad_bus_type) bus",
     },
     {
+        .error_fmt = QERR_BASE_NOT_FOUND,
+        .desc      = "Base '%(base)' not found",
+    },
+    {
         .error_fmt = QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
         .desc      = "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'",
     },
diff --git a/qerror.h b/qerror.h
index b530bc8..8c36ddb 100644
--- a/qerror.h
+++ b/qerror.h
@@ -57,6 +57,9 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_BAD_BUS_FOR_DEVICE \
     "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
 
+#define QERR_BASE_NOT_FOUND \
+    "{ 'class': 'BaseNotFound', 'data': { 'base': %s } }"
+
 #define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
     "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
 
commit e8a6bb9caa5379b0fcaca4e0a12aa6d2913961f3
Author: Marcelo Tosatti <mtosatti at redhat.com>
Date:   Wed Jan 18 14:40:51 2012 +0000

    block: add bdrv_find_backing_image
    
    Add bdrv_find_backing_image: given a BlockDriverState pointer, and an id,
    traverse the backing image chain to locate the id.
    
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 2baac95..3621d11 100644
--- a/block.c
+++ b/block.c
@@ -2595,6 +2595,24 @@ int bdrv_snapshot_load_tmp(BlockDriverState *bs,
     return -ENOTSUP;
 }
 
+BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
+        const char *backing_file)
+{
+    if (!bs->drv) {
+        return NULL;
+    }
+
+    if (bs->backing_hd) {
+        if (strcmp(bs->backing_file, backing_file) == 0) {
+            return bs->backing_hd;
+        } else {
+            return bdrv_find_backing_image(bs->backing_hd, backing_file);
+        }
+    }
+
+    return NULL;
+}
+
 #define NB_SUFFIXES 4
 
 char *get_human_readable_size(char *buf, int buf_size, int64_t size)
diff --git a/block.h b/block.h
index a3b0b80..cae289b 100644
--- a/block.h
+++ b/block.h
@@ -148,6 +148,8 @@ int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
     int nb_sectors, QEMUIOVector *qiov);
 int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t sector_num,
     int nb_sectors, int *pnum);
+BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
+    const char *backing_file);
 int bdrv_truncate(BlockDriverState *bs, int64_t offset);
 int64_t bdrv_getlength(BlockDriverState *bs);
 int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
commit aa398a5c3a4c0fc29baf02aee5283a7fa0f202a3
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Wed Jan 18 14:40:50 2012 +0000

    blockdev: make image streaming safe across hotplug
    
    Unplugging a storage interface like virtio-blk causes the host block
    device to be deleted too.  Long-running operations like block migration
    must take a DriveInfo reference to prevent the BlockDriverState from
    being freed.  For image streaming we can do the same thing.
    
    Note that it is not possible to acquire/release the drive reference in
    block.c where the block job functions live because
    drive_get_ref()/drive_put_ref() are blockdev.c functions.  Calling them
    from block.c would be a layering violation - tools like qemu-img don't
    even link against blockdev.c.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/blockdev.c b/blockdev.c
index d026cd4..2fa0151 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -202,6 +202,37 @@ void drive_get_ref(DriveInfo *dinfo)
     dinfo->refcount++;
 }
 
+typedef struct {
+    QEMUBH *bh;
+    DriveInfo *dinfo;
+} DrivePutRefBH;
+
+static void drive_put_ref_bh(void *opaque)
+{
+    DrivePutRefBH *s = opaque;
+
+    drive_put_ref(s->dinfo);
+    qemu_bh_delete(s->bh);
+    g_free(s);
+}
+
+/*
+ * Release a drive reference in a BH
+ *
+ * It is not possible to use drive_put_ref() from a callback function when the
+ * callers still need the drive.  In such cases we schedule a BH to release the
+ * reference.
+ */
+static void drive_put_ref_bh_schedule(DriveInfo *dinfo)
+{
+    DrivePutRefBH *s;
+
+    s = g_new(DrivePutRefBH, 1);
+    s->bh = qemu_bh_new(drive_put_ref_bh, s);
+    s->dinfo = dinfo;
+    qemu_bh_schedule(s->bh);
+}
+
 static int parse_block_error_action(const char *buf, int is_read)
 {
     if (!strcmp(buf, "ignore")) {
@@ -934,6 +965,8 @@ static void block_stream_cb(void *opaque, int ret)
         monitor_protocol_event(QEVENT_BLOCK_JOB_COMPLETED, obj);
     }
     qobject_decref(obj);
+
+    drive_put_ref_bh_schedule(drive_get_by_blockdev(bs));
 }
 
 void qmp_block_stream(const char *device, bool has_base,
@@ -966,6 +999,11 @@ void qmp_block_stream(const char *device, bool has_base,
         }
     }
 
+    /* Grab a reference so hotplug does not delete the BlockDriverState from
+     * underneath us.
+     */
+    drive_get_ref(drive_get_by_blockdev(bs));
+
     trace_qmp_block_stream(bs, bs->job);
 }
 
commit fb5458cd10a199e55e622a906b24f8085d922c0f
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Wed Jan 18 14:40:49 2012 +0000

    qmp: add query-block-jobs
    
    Add query-block-jobs, which shows the progress of ongoing block device
    operations.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Acked-by: Luiz Capitulino <lcapitulino at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/blockdev.c b/blockdev.c
index d3d6718..d026cd4 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1006,3 +1006,36 @@ void qmp_block_job_cancel(const char *device, Error **errp)
     trace_qmp_block_job_cancel(job);
     block_job_cancel(job);
 }
+
+static void do_qmp_query_block_jobs_one(void *opaque, BlockDriverState *bs)
+{
+    BlockJobInfoList **prev = opaque;
+    BlockJob *job = bs->job;
+
+    if (job) {
+        BlockJobInfoList *elem;
+        BlockJobInfo *info = g_new(BlockJobInfo, 1);
+        *info = (BlockJobInfo){
+            .type   = g_strdup(job->job_type->job_type),
+            .device = g_strdup(bdrv_get_device_name(bs)),
+            .len    = job->len,
+            .offset = job->offset,
+            .speed  = job->speed,
+        };
+
+        elem = g_new0(BlockJobInfoList, 1);
+        elem->value = info;
+
+        (*prev)->next = elem;
+        *prev = elem;
+    }
+}
+
+BlockJobInfoList *qmp_query_block_jobs(Error **errp)
+{
+    /* Dummy is a fake list element for holding the head pointer */
+    BlockJobInfoList dummy = {};
+    BlockJobInfoList *prev = &dummy;
+    bdrv_iterate(do_qmp_query_block_jobs_one, &prev);
+    return dummy.next;
+}
diff --git a/hmp.c b/hmp.c
index 867c338..8ff8c94 100644
--- a/hmp.c
+++ b/hmp.c
@@ -509,6 +509,42 @@ void hmp_info_pci(Monitor *mon)
     qapi_free_PciInfoList(info_list);
 }
 
+void hmp_info_block_jobs(Monitor *mon)
+{
+    BlockJobInfoList *list;
+    Error *err = NULL;
+
+    list = qmp_query_block_jobs(&err);
+    assert(!err);
+
+    if (!list) {
+        monitor_printf(mon, "No active jobs\n");
+        return;
+    }
+
+    while (list) {
+        if (strcmp(list->value->type, "stream") == 0) {
+            monitor_printf(mon, "Streaming device %s: Completed %" PRId64
+                           " of %" PRId64 " bytes, speed limit %" PRId64
+                           " bytes/s\n",
+                           list->value->device,
+                           list->value->offset,
+                           list->value->len,
+                           list->value->speed);
+        } else {
+            monitor_printf(mon, "Type %s, device %s: Completed %" PRId64
+                           " of %" PRId64 " bytes, speed limit %" PRId64
+                           " bytes/s\n",
+                           list->value->type,
+                           list->value->device,
+                           list->value->offset,
+                           list->value->len,
+                           list->value->speed);
+        }
+        list = list->next;
+    }
+}
+
 void hmp_quit(Monitor *mon, const QDict *qdict)
 {
     monitor_suspend(mon);
diff --git a/hmp.h b/hmp.h
index eb4ca82..18eecbd 100644
--- a/hmp.h
+++ b/hmp.h
@@ -32,6 +32,7 @@ void hmp_info_vnc(Monitor *mon);
 void hmp_info_spice(Monitor *mon);
 void hmp_info_balloon(Monitor *mon);
 void hmp_info_pci(Monitor *mon);
+void hmp_info_block_jobs(Monitor *mon);
 void hmp_quit(Monitor *mon, const QDict *qdict);
 void hmp_stop(Monitor *mon, const QDict *qdict);
 void hmp_system_reset(Monitor *mon, const QDict *qdict);
diff --git a/monitor.c b/monitor.c
index 9424c31..aadbdcb 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2318,6 +2318,13 @@ static mon_cmd_t info_cmds[] = {
         .mhandler.info = hmp_info_blockstats,
     },
     {
+        .name       = "block-jobs",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show progress of ongoing block device operations",
+        .mhandler.info = hmp_info_block_jobs,
+    },
+    {
         .name       = "registers",
         .args_type  = "",
         .params     = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index 02c4e22..3f72c2c 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -845,6 +845,38 @@
 { 'command': 'query-pci', 'returns': ['PciInfo'] }
 
 ##
+# @BlockJobInfo:
+#
+# Information about a long-running block device operation.
+#
+# @type: the job type ('stream' for image streaming)
+#
+# @device: the block device name
+#
+# @len: the maximum progress value
+#
+# @offset: the current progress value
+#
+# @speed: the rate limit, bytes per second
+#
+# Since: 1.1
+##
+{ 'type': 'BlockJobInfo',
+  'data': {'type': 'str', 'device': 'str', 'len': 'int',
+           'offset': 'int', 'speed': 'int'} }
+
+##
+# @query-block-jobs:
+#
+# Return information about long-running block device operations.
+#
+# Returns: a list of @BlockJobInfo for each active block job
+#
+# Since: 1.1
+##
+{ 'command': 'query-block-jobs', 'returns': ['BlockJobInfo'] }
+
+##
 # @quit:
 #
 # This command will cause the QEMU process to exit gracefully.  While every
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 0795c5d..bd6b641 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2014,6 +2014,12 @@ EQMP
     },
 
     {
+        .name       = "query-block-jobs",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_block_jobs,
+    },
+
+    {
         .name       = "qom-list",
         .args_type  = "path:s",
         .mhandler.cmd_new = qmp_marshal_input_qom_list,
commit 370521a1d6f5537ea7271c119f3fbb7b0fa57063
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Wed Jan 18 14:40:48 2012 +0000

    qmp: add block_job_cancel command
    
    Add block_job_cancel, which stops an active block streaming operation.
    When the operation has been cancelled the new BLOCK_JOB_CANCELLED event
    is emitted.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Acked-by: Luiz Capitulino <lcapitulino at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt
index 0cd2275..06cb404 100644
--- a/QMP/qmp-events.txt
+++ b/QMP/qmp-events.txt
@@ -293,3 +293,27 @@ Example:
                "len": 10737418240, "offset": 10737418240,
                "speed": 0 },
      "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+
+
+BLOCK_JOB_CANCELLED
+-------------------
+
+Emitted when a block job has been cancelled.
+
+Data:
+
+- "type":     Job type ("stream" for image streaming, json-string)
+- "device":   Device name (json-string)
+- "len":      Maximum progress value (json-int)
+- "offset":   Current progress value (json-int)
+              On success this is equal to len.
+              On failure this is less than len.
+- "speed":    Rate limit, bytes per second (json-int)
+
+Example:
+
+{ "event": "BLOCK_JOB_CANCELLED",
+     "data": { "type": "stream", "device": "virtio-disk0",
+               "len": 10737418240, "offset": 134217728,
+               "speed": 0 },
+     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
diff --git a/blockdev.c b/blockdev.c
index 4c8fcdd..d3d6718 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -928,7 +928,11 @@ static void block_stream_cb(void *opaque, int ret)
         qdict_put(dict, "error", qstring_from_str(strerror(-ret)));
     }
 
-    monitor_protocol_event(QEVENT_BLOCK_JOB_COMPLETED, obj);
+    if (block_job_is_cancelled(bs->job)) {
+        monitor_protocol_event(QEVENT_BLOCK_JOB_CANCELLED, obj);
+    } else {
+        monitor_protocol_event(QEVENT_BLOCK_JOB_COMPLETED, obj);
+    }
     qobject_decref(obj);
 }
 
@@ -989,3 +993,16 @@ void qmp_block_job_set_speed(const char *device, int64_t value, Error **errp)
         error_set(errp, QERR_NOT_SUPPORTED);
     }
 }
+
+void qmp_block_job_cancel(const char *device, Error **errp)
+{
+    BlockJob *job = find_block_job(device);
+
+    if (!job) {
+        error_set(errp, QERR_DEVICE_NOT_ACTIVE, device);
+        return;
+    }
+
+    trace_qmp_block_job_cancel(job);
+    block_job_cancel(job);
+}
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 813705e..573b823 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -98,6 +98,20 @@ Set maximum speed for a background block operation.
 ETEXI
 
     {
+        .name       = "block_job_cancel",
+        .args_type  = "device:B",
+        .params     = "device",
+        .help       = "stop an active block streaming operation",
+        .mhandler.cmd = hmp_block_job_cancel,
+    },
+
+STEXI
+ at item block_job_cancel
+ at findex block_job_cancel
+Stop an active block streaming operation.
+ETEXI
+
+    {
         .name       = "eject",
         .args_type  = "force:-f,device:B",
         .params     = "[-f] device",
diff --git a/hmp.c b/hmp.c
index bf3d9df..867c338 100644
--- a/hmp.c
+++ b/hmp.c
@@ -805,3 +805,13 @@ void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict)
 
     hmp_handle_error(mon, &error);
 }
+
+void hmp_block_job_cancel(Monitor *mon, const QDict *qdict)
+{
+    Error *error = NULL;
+    const char *device = qdict_get_str(qdict, "device");
+
+    qmp_block_job_cancel(device, &error);
+
+    hmp_handle_error(mon, &error);
+}
diff --git a/hmp.h b/hmp.h
index edd9020..eb4ca82 100644
--- a/hmp.h
+++ b/hmp.h
@@ -56,5 +56,6 @@ void hmp_change(Monitor *mon, const QDict *qdict);
 void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
 void hmp_block_stream(Monitor *mon, const QDict *qdict);
 void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
+void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/monitor.c b/monitor.c
index 3d8cbfb..9424c31 100644
--- a/monitor.c
+++ b/monitor.c
@@ -482,6 +482,9 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
         case QEVENT_BLOCK_JOB_COMPLETED:
             event_name = "BLOCK_JOB_COMPLETED";
             break;
+        case QEVENT_BLOCK_JOB_CANCELLED:
+            event_name = "BLOCK_JOB_CANCELLED";
+            break;
         default:
             abort();
             break;
diff --git a/monitor.h b/monitor.h
index 34d00d1..b72ea07 100644
--- a/monitor.h
+++ b/monitor.h
@@ -37,6 +37,7 @@ typedef enum MonitorEvent {
     QEVENT_SPICE_INITIALIZED,
     QEVENT_SPICE_DISCONNECTED,
     QEVENT_BLOCK_JOB_COMPLETED,
+    QEVENT_BLOCK_JOB_CANCELLED,
     QEVENT_MAX,
 } MonitorEvent;
 
diff --git a/qapi-schema.json b/qapi-schema.json
index d9f66c6..02c4e22 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1487,3 +1487,32 @@
 ##
 { 'command': 'block_job_set_speed',
   'data': { 'device': 'str', 'value': 'int' } }
+
+##
+# @block_job_cancel:
+#
+# Stop an active block streaming operation.
+#
+# This command returns immediately after marking the active block streaming
+# operation for cancellation.  It is an error to call this command if no
+# operation is in progress.
+#
+# The operation will cancel as soon as possible and then emit the
+# BLOCK_JOB_CANCELLED event.  Before that happens the job is still visible when
+# enumerated using query-block-jobs.
+#
+# The image file retains its backing file unless the streaming operation happens
+# to complete just as it is being cancelled.
+#
+# A new block streaming operation can be started at a later time to finish
+# copying all data from the backing file.
+#
+# @device: the device name
+#
+# Returns: Nothing on success
+#          If streaming is not active on this device, DeviceNotActive
+#          If cancellation already in progress, DeviceInUse
+#
+# Since: 1.1
+##
+{ 'command': 'block_job_cancel', 'data': { 'device': 'str' } }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index e4615ca..0795c5d 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -661,6 +661,12 @@ EQMP
     },
 
     {
+        .name       = "block_job_cancel",
+        .args_type  = "device:B",
+        .mhandler.cmd_new = qmp_marshal_input_block_job_cancel,
+    },
+
+    {
         .name       = "blockdev-snapshot-sync",
         .args_type  = "device:B,snapshot-file:s,format:s?",
         .mhandler.cmd_new = qmp_marshal_input_blockdev_snapshot_sync,
diff --git a/trace-events b/trace-events
index 5edba21..ad77e0a 100644
--- a/trace-events
+++ b/trace-events
@@ -75,6 +75,7 @@ stream_one_iteration(void *s, int64_t sector_num, int nb_sectors, int is_allocat
 stream_start(void *bs, void *base, void *s, void *co, void *opaque) "bs %p base %p s %p co %p opaque %p"
 
 # blockdev.c
+qmp_block_job_cancel(void *job) "job %p"
 block_stream_cb(void *bs, void *job, int ret) "bs %p job %p ret %d"
 qmp_block_stream(void *bs, void *job) "bs %p job %p"
 
commit 2d47c6e9aa2475807913bd46dfca55980cca9fb4
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Wed Jan 18 14:40:47 2012 +0000

    qmp: add block_job_set_speed command
    
    Add block_job_set_speed, which sets the maximum speed for a background
    block operation.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Acked-by: Luiz Capitulino <lcapitulino at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/blockdev.c b/blockdev.c
index 06f179e..4c8fcdd 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -964,3 +964,28 @@ void qmp_block_stream(const char *device, bool has_base,
 
     trace_qmp_block_stream(bs, bs->job);
 }
+
+static BlockJob *find_block_job(const char *device)
+{
+    BlockDriverState *bs;
+
+    bs = bdrv_find(device);
+    if (!bs || !bs->job) {
+        return NULL;
+    }
+    return bs->job;
+}
+
+void qmp_block_job_set_speed(const char *device, int64_t value, Error **errp)
+{
+    BlockJob *job = find_block_job(device);
+
+    if (!job) {
+        error_set(errp, QERR_DEVICE_NOT_ACTIVE, device);
+        return;
+    }
+
+    if (block_job_set_speed(job, value) < 0) {
+        error_set(errp, QERR_NOT_SUPPORTED);
+    }
+}
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 5f09594..813705e 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -84,6 +84,20 @@ Copy data from a backing file into a block device.
 ETEXI
 
     {
+        .name       = "block_job_set_speed",
+        .args_type  = "device:B,value:o",
+        .params     = "device value",
+        .help       = "set maximum speed for a background block operation",
+        .mhandler.cmd = hmp_block_job_set_speed,
+    },
+
+STEXI
+ at item block_job_set_stream
+ at findex block_job_set_stream
+Set maximum speed for a background block operation.
+ETEXI
+
+    {
         .name       = "eject",
         .args_type  = "force:-f,device:B",
         .params     = "[-f] device",
diff --git a/hmp.c b/hmp.c
index cde8d7a..bf3d9df 100644
--- a/hmp.c
+++ b/hmp.c
@@ -794,3 +794,14 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict)
 
     hmp_handle_error(mon, &error);
 }
+
+void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict)
+{
+    Error *error = NULL;
+    const char *device = qdict_get_str(qdict, "device");
+    int64_t value = qdict_get_int(qdict, "value");
+
+    qmp_block_job_set_speed(device, value, &error);
+
+    hmp_handle_error(mon, &error);
+}
diff --git a/hmp.h b/hmp.h
index 9234f28..edd9020 100644
--- a/hmp.h
+++ b/hmp.h
@@ -55,5 +55,6 @@ void hmp_eject(Monitor *mon, const QDict *qdict);
 void hmp_change(Monitor *mon, const QDict *qdict);
 void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
 void hmp_block_stream(Monitor *mon, const QDict *qdict);
+void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index 9a1d9a9..d9f66c6 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1465,3 +1465,25 @@
 # Since: 1.1
 ##
 { 'command': 'block_stream', 'data': { 'device': 'str', '*base': 'str' } }
+
+##
+# @block_job_set_speed:
+#
+# Set maximum speed for a background block operation.
+#
+# This command can only be issued when there is an active block job.
+#
+# Throttling can be disabled by setting the speed to 0.
+#
+# @device: the device name
+#
+# @value:  the maximum speed, in bytes per second
+#
+# Returns: Nothing on success
+#          If the job type does not support throttling, NotSupported
+#          If streaming is not active on this device, DeviceNotActive
+#
+# Since: 1.1
+##
+{ 'command': 'block_job_set_speed',
+  'data': { 'device': 'str', 'value': 'int' } }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 0dfc80e..e4615ca 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -655,6 +655,12 @@ EQMP
     },
 
     {
+        .name       = "block_job_set_speed",
+        .args_type  = "device:B,value:o",
+        .mhandler.cmd_new = qmp_marshal_input_block_job_set_speed,
+    },
+
+    {
         .name       = "blockdev-snapshot-sync",
         .args_type  = "device:B,snapshot-file:s,format:s?",
         .mhandler.cmd_new = qmp_marshal_input_blockdev_snapshot_sync,
commit 12bd451fe0be83474910bb63b5874458141d4230
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Wed Jan 18 14:40:46 2012 +0000

    qmp: add block_stream command
    
    Add the block_stream command, which starts copy backing file contents
    into the image file.  Also add the BLOCK_JOB_COMPLETED QMP event which
    is emitted when image streaming completes.  Later patches add control
    over the background copy speed, cancelation, and querying running
    streaming operations.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Acked-by: Luiz Capitulino <lcapitulino at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt
index af586ec..0cd2275 100644
--- a/QMP/qmp-events.txt
+++ b/QMP/qmp-events.txt
@@ -264,3 +264,32 @@ Example:
 
 Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
 followed respectively by the RESET, SHUTDOWN, or STOP events.
+
+
+BLOCK_JOB_COMPLETED
+-------------------
+
+Emitted when a block job has completed.
+
+Data:
+
+- "type":     Job type ("stream" for image streaming, json-string)
+- "device":   Device name (json-string)
+- "len":      Maximum progress value (json-int)
+- "offset":   Current progress value (json-int)
+              On success this is equal to len.
+              On failure this is less than len.
+- "speed":    Rate limit, bytes per second (json-int)
+- "error":    Error message (json-string, optional)
+              Only present on failure.  This field contains a human-readable
+              error message.  There are no semantics other than that streaming
+              has failed and clients should not try to interpret the error
+              string.
+
+Example:
+
+{ "event": "BLOCK_JOB_COMPLETED",
+     "data": { "type": "stream", "device": "virtio-disk0",
+               "len": 10737418240, "offset": 10737418240,
+               "speed": 0 },
+     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
diff --git a/blockdev.c b/blockdev.c
index 0499ee6..06f179e 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -13,9 +13,11 @@
 #include "qerror.h"
 #include "qemu-option.h"
 #include "qemu-config.h"
+#include "qemu-objects.h"
 #include "sysemu.h"
 #include "block_int.h"
 #include "qmp-commands.h"
+#include "trace.h"
 
 static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
 
@@ -897,3 +899,68 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp)
         break;
     }
 }
+
+static QObject *qobject_from_block_job(BlockJob *job)
+{
+    return qobject_from_jsonf("{ 'type': %s,"
+                              "'device': %s,"
+                              "'len': %" PRId64 ","
+                              "'offset': %" PRId64 ","
+                              "'speed': %" PRId64 " }",
+                              job->job_type->job_type,
+                              bdrv_get_device_name(job->bs),
+                              job->len,
+                              job->offset,
+                              job->speed);
+}
+
+static void block_stream_cb(void *opaque, int ret)
+{
+    BlockDriverState *bs = opaque;
+    QObject *obj;
+
+    trace_block_stream_cb(bs, bs->job, ret);
+
+    assert(bs->job);
+    obj = qobject_from_block_job(bs->job);
+    if (ret < 0) {
+        QDict *dict = qobject_to_qdict(obj);
+        qdict_put(dict, "error", qstring_from_str(strerror(-ret)));
+    }
+
+    monitor_protocol_event(QEVENT_BLOCK_JOB_COMPLETED, obj);
+    qobject_decref(obj);
+}
+
+void qmp_block_stream(const char *device, bool has_base,
+                      const char *base, Error **errp)
+{
+    BlockDriverState *bs;
+    int ret;
+
+    bs = bdrv_find(device);
+    if (!bs) {
+        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+        return;
+    }
+
+    /* Base device not supported */
+    if (base) {
+        error_set(errp, QERR_NOT_SUPPORTED);
+        return;
+    }
+
+    ret = stream_start(bs, NULL, block_stream_cb, bs);
+    if (ret < 0) {
+        switch (ret) {
+        case -EBUSY:
+            error_set(errp, QERR_DEVICE_IN_USE, device);
+            return;
+        default:
+            error_set(errp, QERR_NOT_SUPPORTED);
+            return;
+        }
+    }
+
+    trace_qmp_block_stream(bs, bs->job);
+}
diff --git a/hmp-commands.hx b/hmp-commands.hx
index e6506fc..5f09594 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -69,6 +69,19 @@ but should be used with extreme caution.  Note that this command only
 resizes image files, it can not resize block devices like LVM volumes.
 ETEXI
 
+    {
+        .name       = "block_stream",
+        .args_type  = "device:B,base:s?",
+        .params     = "device [base]",
+        .help       = "copy data from a backing file into a block device",
+        .mhandler.cmd = hmp_block_stream,
+    },
+
+STEXI
+ at item block_stream
+ at findex block_stream
+Copy data from a backing file into a block device.
+ETEXI
 
     {
         .name       = "eject",
diff --git a/hmp.c b/hmp.c
index 4664dbe..cde8d7a 100644
--- a/hmp.c
+++ b/hmp.c
@@ -783,3 +783,14 @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
                               qdict_get_int(qdict, "iops_wr"), &err);
     hmp_handle_error(mon, &err);
 }
+
+void hmp_block_stream(Monitor *mon, const QDict *qdict)
+{
+    Error *error = NULL;
+    const char *device = qdict_get_str(qdict, "device");
+    const char *base = qdict_get_try_str(qdict, "base");
+
+    qmp_block_stream(device, base != NULL, base, &error);
+
+    hmp_handle_error(mon, &error);
+}
diff --git a/hmp.h b/hmp.h
index aab0b1f..9234f28 100644
--- a/hmp.h
+++ b/hmp.h
@@ -54,5 +54,6 @@ void hmp_expire_password(Monitor *mon, const QDict *qdict);
 void hmp_eject(Monitor *mon, const QDict *qdict);
 void hmp_change(Monitor *mon, const QDict *qdict);
 void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
+void hmp_block_stream(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/monitor.c b/monitor.c
index 187083c..3d8cbfb 100644
--- a/monitor.c
+++ b/monitor.c
@@ -479,6 +479,9 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
         case QEVENT_SPICE_DISCONNECTED:
             event_name = "SPICE_DISCONNECTED";
             break;
+        case QEVENT_BLOCK_JOB_COMPLETED:
+            event_name = "BLOCK_JOB_COMPLETED";
+            break;
         default:
             abort();
             break;
diff --git a/monitor.h b/monitor.h
index 887c472..34d00d1 100644
--- a/monitor.h
+++ b/monitor.h
@@ -36,6 +36,7 @@ typedef enum MonitorEvent {
     QEVENT_SPICE_CONNECTED,
     QEVENT_SPICE_INITIALIZED,
     QEVENT_SPICE_DISCONNECTED,
+    QEVENT_BLOCK_JOB_COMPLETED,
     QEVENT_MAX,
 } MonitorEvent;
 
diff --git a/qapi-schema.json b/qapi-schema.json
index 735eb35..9a1d9a9 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1434,3 +1434,34 @@
 { 'command': 'block_set_io_throttle',
   'data': { 'device': 'str', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
             'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int' } }
+
+# @block_stream:
+#
+# Copy data from a backing file into a block device.
+#
+# The block streaming operation is performed in the background until the entire
+# backing file has been copied.  This command returns immediately once streaming
+# has started.  The status of ongoing block streaming operations can be checked
+# with query-block-jobs.  The operation can be stopped before it has completed
+# using the block_job_cancel command.
+#
+# If a base file is specified then sectors are not copied from that base file and
+# its backing chain.  When streaming completes the image file will have the base
+# file as its backing file.  This can be used to stream a subset of the backing
+# file chain instead of flattening the entire image.
+#
+# On successful completion the image file is updated to drop the backing file
+# and the BLOCK_JOB_COMPLETED event is emitted.
+#
+# @device: the device name
+#
+# @base:   #optional the common backing file name
+#
+# Returns: Nothing on success
+#          If streaming is already active on this device, DeviceInUse
+#          If @device does not exist, DeviceNotFound
+#          If image streaming is not supported by this device, NotSupported
+#
+# Since: 1.1
+##
+{ 'command': 'block_stream', 'data': { 'device': 'str', '*base': 'str' } }
diff --git a/qerror.c b/qerror.c
index 3d95383..2c60e10 100644
--- a/qerror.c
+++ b/qerror.c
@@ -197,6 +197,10 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "No '%(bus)' bus found for device '%(device)'",
     },
     {
+        .error_fmt = QERR_NOT_SUPPORTED,
+        .desc      = "Not supported",
+    },
+    {
         .error_fmt = QERR_OPEN_FILE_FAILED,
         .desc      = "Could not open '%(filename)'",
     },
diff --git a/qerror.h b/qerror.h
index 89160dd..b530bc8 100644
--- a/qerror.h
+++ b/qerror.h
@@ -168,6 +168,9 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_NO_BUS_FOR_DEVICE \
     "{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }"
 
+#define QERR_NOT_SUPPORTED \
+    "{ 'class': 'NotSupported', 'data': {} }"
+
 #define QERR_OPEN_FILE_FAILED \
     "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }"
 
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 799e655..0dfc80e 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -649,6 +649,12 @@ Example:
 EQMP
 
     {
+        .name       = "block_stream",
+        .args_type  = "device:B,base:s?",
+        .mhandler.cmd_new = qmp_marshal_input_block_stream,
+    },
+
+    {
         .name       = "blockdev-snapshot-sync",
         .args_type  = "device:B,snapshot-file:s,format:s?",
         .mhandler.cmd_new = qmp_marshal_input_blockdev_snapshot_sync,
diff --git a/trace-events b/trace-events
index f6a3cd1..5edba21 100644
--- a/trace-events
+++ b/trace-events
@@ -74,6 +74,10 @@ bdrv_co_do_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t c
 stream_one_iteration(void *s, int64_t sector_num, int nb_sectors, int is_allocated) "s %p sector_num %"PRId64" nb_sectors %d is_allocated %d"
 stream_start(void *bs, void *base, void *s, void *co, void *opaque) "bs %p base %p s %p co %p opaque %p"
 
+# blockdev.c
+block_stream_cb(void *bs, void *job, int ret) "bs %p job %p ret %d"
+qmp_block_stream(void *bs, void *job) "bs %p job %p"
+
 # hw/virtio-blk.c
 virtio_blk_req_complete(void *req, int status) "req %p status %d"
 virtio_blk_rw_complete(void *req, int ret) "req %p ret %d"
commit 2488514cef2e952370cf8966c805259a3e9417d4
Author: Rob Herring <rob.herring at calxeda.com>
Date:   Thu Jan 26 11:43:49 2012 +0000

    arm: SoC model for Calxeda Highbank
    
    Adds support for Calxeda's Highbank SoC.
    
    Signed-off-by: Rob Herring <rob.herring at calxeda.com>
    Signed-off-by: Mark Langsdorf <mark.langsdorf at calxeda.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/Makefile.target b/Makefile.target
index 063ec54..3c85085 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -339,6 +339,7 @@ obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
 obj-arm-y += arm_l2x0.o
 obj-arm-y += arm_mptimer.o
 obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
+obj-arm-y += highbank.o
 obj-arm-y += pl061.o
 obj-arm-y += xgmac.o
 obj-arm-y += arm-semi.o
diff --git a/hw/highbank.c b/hw/highbank.c
new file mode 100644
index 0000000..136297c
--- /dev/null
+++ b/hw/highbank.c
@@ -0,0 +1,330 @@
+/*
+ * 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 SysBusDeviceInfo highbank_regs_info = {
+    .init       = highbank_regs_init,
+    .qdev.name  = "highbank-regs",
+    .qdev.desc  = "Calxeda Highbank registers",
+    .qdev.size  = sizeof(HighbankRegsState),
+    .qdev.vmsd  = &vmstate_highbank_regs,
+    .qdev.reset = highbank_regs_reset,
+};
+
+static void highbank_regs_register_device(void)
+{
+    sysbus_register_withprop(&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);
commit f8414cb5c8343bdacfee53ac9e255831aed882fe
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Jan 26 11:43:48 2012 +0000

    arm_boot: support board IDs more than 16 bits wide
    
    Support passing a board ID value to the kernel in r1
    that is more than 16 bits wide. This is needed to pass
    the '-1 == invalid' value for boards which only support
    device tree booting.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Tested-by: Mark Langsdorf <mark.langsdorf at calxeda.com>

diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index 35ca22f..5f163fd 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -20,10 +20,10 @@
 /* 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.  */
 };
@@ -301,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++) {
commit 9d5ba9bfbc1ad9b743b40fa4f40624437f46b287
Author: Mark Langsdorf <mark.langsdorf at calxeda.com>
Date:   Thu Jan 26 11:43:48 2012 +0000

    arm: add secondary cpu boot callbacks to arm_boot.c
    
    Create two functions, write_secondary_boot() and secondary_cpu_reset_hook(),
    to allow platforms more control of how secondary CPUs are brought up. The
    new functions default to NULL and aren't called unless they are populated
    so there are no changes to existing platform models.
    
    Signed-off-by: Mark Langsdorf <mark.langsdorf at calxeda.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/arm-misc.h b/hw/arm-misc.h
index 6e8ae6b..5e5204b 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/arm_boot.c b/hw/arm_boot.c
index bf509a8..35ca22f 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -28,8 +28,20 @@ static uint32_t bootloader[] = {
   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;
 
@@ -273,13 +311,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;
     }
commit d9fa31a3e20155152ae653cb6b6e6bd7db126e5c
Author: Rob Herring <rob.herring at calxeda.com>
Date:   Thu Jan 26 11:43:47 2012 +0000

    ahci: add support for non-PCI based controllers
    
    Add support for ahci on sysbus.
    
    Signed-off-by: Rob Herring <rob.herring at calxeda.com>
    Signed-off-by: Mark Langsdorf <mark.langsdorf at calxeda.com>
    Reviewed-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 0af201d..0309dd6 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,46 @@ 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 SysBusDeviceInfo sysbus_ahci_info = {
+    .qdev.name    = "sysbus-ahci",
+    .qdev.size    = sizeof(SysbusAHCIState),
+    .qdev.vmsd    = &vmstate_sysbus_ahci,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("num-ports", SysbusAHCIState, num_ports, 1),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+    .init         = sysbus_ahci_init,
+
+
+};
+
+static void sysbus_ahci_register(void)
+{
+    sysbus_register_withprop(&sysbus_ahci_info);
+}
+
+device_init(sysbus_ahci_register);
commit 4c0e167c9dd354fa161b3e8d315077c34ecaf33a
Author: Rob Herring <rob.herring at calxeda.com>
Date:   Thu Jan 26 11:43:47 2012 +0000

    Add xgmac ethernet model
    
    This adds very basic support for the xgmac ethernet core. Missing things
    include:
    
    - statistics counters
    - WoL support
    - rx checksum offload
    - chained descriptors (only linear descriptor ring)
    - broadcast and multicast handling
    
    Signed-off-by: Rob Herring <rob.herring at calxeda.com>
    Signed-off-by: Mark Langsdorf <mark.langsdorf at calxeda.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/Makefile.target b/Makefile.target
index e554d33..063ec54 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -340,6 +340,7 @@ obj-arm-y += arm_l2x0.o
 obj-arm-y += arm_mptimer.o
 obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
 obj-arm-y += pl061.o
+obj-arm-y += xgmac.o
 obj-arm-y += arm-semi.o
 obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
 obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
diff --git a/hw/xgmac.c b/hw/xgmac.c
new file mode 100644
index 0000000..be63a7d
--- /dev/null
+++ b/hw/xgmac.c
@@ -0,0 +1,421 @@
+/*
+ * 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,
+                          dev->qdev.info->name, 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 SysBusDeviceInfo xgmac_enet_info = {
+    .init = xgmac_enet_init,
+    .qdev.name  = "xgmac",
+    .qdev.size  = sizeof(struct XgmacState),
+    .qdev.vmsd = &vmstate_xgmac,
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(struct XgmacState, conf),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+static void xgmac_enet_register(void)
+{
+    sysbus_register_withprop(&xgmac_enet_info);
+}
+
+device_init(xgmac_enet_register)
commit 5094a6c016f6e7a4fc800816d716e10ce2331396
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Wed Jan 18 14:40:45 2012 +0000

    block: rate-limit streaming operations
    
    This patch implements rate-limiting for image streaming.  If we've
    exceeded the bandwidth quota for a 100 ms time slice we sleep the
    coroutine until the next slice begins.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/stream.c b/block/stream.c
index 3a99094..b54b0b7 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -23,8 +23,39 @@ enum {
     STREAM_BUFFER_SIZE = 512 * 1024, /* in bytes */
 };
 
+#define SLICE_TIME 100000000ULL /* ns */
+
+typedef struct {
+    int64_t next_slice_time;
+    uint64_t slice_quota;
+    uint64_t dispatched;
+} RateLimit;
+
+static int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n)
+{
+    int64_t delay_ns = 0;
+    int64_t now = qemu_get_clock_ns(rt_clock);
+
+    if (limit->next_slice_time < now) {
+        limit->next_slice_time = now + SLICE_TIME;
+        limit->dispatched = 0;
+    }
+    if (limit->dispatched + n > limit->slice_quota) {
+        delay_ns = limit->next_slice_time - now;
+    } else {
+        limit->dispatched += n;
+    }
+    return delay_ns;
+}
+
+static void ratelimit_set_speed(RateLimit *limit, uint64_t speed)
+{
+    limit->slice_quota = speed / (1000000000ULL / SLICE_TIME);
+}
+
 typedef struct StreamBlockJob {
     BlockJob common;
+    RateLimit limit;
     BlockDriverState *base;
 } StreamBlockJob;
 
@@ -72,20 +103,24 @@ static void coroutine_fn stream_run(void *opaque)
     }
 
     for (sector_num = 0; sector_num < end; sector_num += n) {
+retry:
         if (block_job_is_cancelled(&s->common)) {
             break;
         }
 
-        /* TODO rate-limit */
-        /* Note that even when no rate limit is applied we need to yield with
-         * no pending I/O here so that qemu_aio_flush() is able to return.
-         */
-        co_sleep_ns(rt_clock, 0);
-
         ret = bdrv_co_is_allocated(bs, sector_num,
                                    STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n);
         trace_stream_one_iteration(s, sector_num, n, ret);
         if (ret == 0) {
+            if (s->common.speed) {
+                uint64_t delay_ns = ratelimit_calculate_delay(&s->limit, n);
+                if (delay_ns > 0) {
+                    co_sleep_ns(rt_clock, delay_ns);
+
+                    /* Recheck cancellation and that sectors are unallocated */
+                    goto retry;
+                }
+            }
             ret = stream_populate(bs, sector_num, n, buf);
         }
         if (ret < 0) {
@@ -94,6 +129,11 @@ static void coroutine_fn stream_run(void *opaque)
 
         /* Publish progress */
         s->common.offset += n * BDRV_SECTOR_SIZE;
+
+        /* Note that even when no rate limit is applied we need to yield
+         * with no pending I/O here so that qemu_aio_flush() returns.
+         */
+        co_sleep_ns(rt_clock, 0);
     }
 
     if (!base) {
@@ -108,9 +148,22 @@ static void coroutine_fn stream_run(void *opaque)
     block_job_complete(&s->common, ret);
 }
 
+static int stream_set_speed(BlockJob *job, int64_t value)
+{
+    StreamBlockJob *s = container_of(job, StreamBlockJob, common);
+
+    if (value < 0) {
+        return -EINVAL;
+    }
+    job->speed = value;
+    ratelimit_set_speed(&s->limit, value / BDRV_SECTOR_SIZE);
+    return 0;
+}
+
 static BlockJobType stream_job_type = {
     .instance_size = sizeof(StreamBlockJob),
     .job_type      = "stream",
+    .set_speed     = stream_set_speed,
 };
 
 int stream_start(BlockDriverState *bs, BlockDriverState *base,
commit 4f1043b4ffdd6f130cab7c1d8d59d833a475adac
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Wed Jan 18 14:40:44 2012 +0000

    block: add image streaming block job
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/Makefile.objs b/Makefile.objs
index 48d1477..06a147b 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -35,6 +35,7 @@ block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow
 block-nested-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
 block-nested-y += qed-check.o
 block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
+block-nested-y += stream.o
 block-nested-$(CONFIG_WIN32) += raw-win32.o
 block-nested-$(CONFIG_POSIX) += raw-posix.o
 block-nested-$(CONFIG_LIBISCSI) += iscsi.o
diff --git a/block/stream.c b/block/stream.c
new file mode 100644
index 0000000..3a99094
--- /dev/null
+++ b/block/stream.c
@@ -0,0 +1,133 @@
+/*
+ * Image streaming
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "trace.h"
+#include "block_int.h"
+
+enum {
+    /*
+     * Size of data buffer for populating the image file.  This should be large
+     * enough to process multiple clusters in a single call, so that populating
+     * contiguous regions of the image is efficient.
+     */
+    STREAM_BUFFER_SIZE = 512 * 1024, /* in bytes */
+};
+
+typedef struct StreamBlockJob {
+    BlockJob common;
+    BlockDriverState *base;
+} StreamBlockJob;
+
+static int coroutine_fn stream_populate(BlockDriverState *bs,
+                                        int64_t sector_num, int nb_sectors,
+                                        void *buf)
+{
+    struct iovec iov = {
+        .iov_base = buf,
+        .iov_len  = nb_sectors * BDRV_SECTOR_SIZE,
+    };
+    QEMUIOVector qiov;
+
+    qemu_iovec_init_external(&qiov, &iov, 1);
+
+    /* Copy-on-read the unallocated clusters */
+    return bdrv_co_copy_on_readv(bs, sector_num, nb_sectors, &qiov);
+}
+
+static void coroutine_fn stream_run(void *opaque)
+{
+    StreamBlockJob *s = opaque;
+    BlockDriverState *bs = s->common.bs;
+    int64_t sector_num, end;
+    int ret = 0;
+    int n;
+    void *buf;
+
+    s->common.len = bdrv_getlength(bs);
+    if (s->common.len < 0) {
+        block_job_complete(&s->common, s->common.len);
+        return;
+    }
+
+    end = s->common.len >> BDRV_SECTOR_BITS;
+    buf = qemu_blockalign(bs, STREAM_BUFFER_SIZE);
+
+    /* Turn on copy-on-read for the whole block device so that guest read
+     * requests help us make progress.  Only do this when copying the entire
+     * backing chain since the copy-on-read operation does not take base into
+     * account.
+     */
+    if (!base) {
+        bdrv_enable_copy_on_read(bs);
+    }
+
+    for (sector_num = 0; sector_num < end; sector_num += n) {
+        if (block_job_is_cancelled(&s->common)) {
+            break;
+        }
+
+        /* TODO rate-limit */
+        /* Note that even when no rate limit is applied we need to yield with
+         * no pending I/O here so that qemu_aio_flush() is able to return.
+         */
+        co_sleep_ns(rt_clock, 0);
+
+        ret = bdrv_co_is_allocated(bs, sector_num,
+                                   STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n);
+        trace_stream_one_iteration(s, sector_num, n, ret);
+        if (ret == 0) {
+            ret = stream_populate(bs, sector_num, n, buf);
+        }
+        if (ret < 0) {
+            break;
+        }
+
+        /* Publish progress */
+        s->common.offset += n * BDRV_SECTOR_SIZE;
+    }
+
+    if (!base) {
+        bdrv_disable_copy_on_read(bs);
+    }
+
+    if (sector_num == end && ret == 0) {
+        ret = bdrv_change_backing_file(bs, NULL, NULL);
+    }
+
+    qemu_vfree(buf);
+    block_job_complete(&s->common, ret);
+}
+
+static BlockJobType stream_job_type = {
+    .instance_size = sizeof(StreamBlockJob),
+    .job_type      = "stream",
+};
+
+int stream_start(BlockDriverState *bs, BlockDriverState *base,
+                 BlockDriverCompletionFunc *cb, void *opaque)
+{
+    StreamBlockJob *s;
+    Coroutine *co;
+
+    s = block_job_create(&stream_job_type, bs, cb, opaque);
+    if (!s) {
+        return -EBUSY; /* bs must already be in use */
+    }
+
+    s->base = base;
+
+    co = qemu_coroutine_create(stream_run);
+    trace_stream_start(bs, base, s, co, opaque);
+    qemu_coroutine_enter(co, s);
+    return 0;
+}
diff --git a/block_int.h b/block_int.h
index 3566acb..4f63870 100644
--- a/block_int.h
+++ b/block_int.h
@@ -327,4 +327,7 @@ int block_job_set_speed(BlockJob *job, int64_t value);
 void block_job_cancel(BlockJob *job);
 bool block_job_is_cancelled(BlockJob *job);
 
+int stream_start(BlockDriverState *bs, BlockDriverState *base,
+                 BlockDriverCompletionFunc *cb, void *opaque);
+
 #endif /* BLOCK_INT_H */
diff --git a/trace-events b/trace-events
index 035d08f..f6a3cd1 100644
--- a/trace-events
+++ b/trace-events
@@ -70,6 +70,10 @@ bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"
 bdrv_co_io_em(void *bs, int64_t sector_num, int nb_sectors, int is_write, void *acb) "bs %p sector_num %"PRId64" nb_sectors %d is_write %d acb %p"
 bdrv_co_do_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t cluster_sector_num, int cluster_nb_sectors) "bs %p sector_num %"PRId64" nb_sectors %d cluster_sector_num %"PRId64" cluster_nb_sectors %d"
 
+# block/stream.c
+stream_one_iteration(void *s, int64_t sector_num, int nb_sectors, int is_allocated) "s %p sector_num %"PRId64" nb_sectors %d is_allocated %d"
+stream_start(void *bs, void *base, void *s, void *co, void *opaque) "bs %p base %p s %p co %p opaque %p"
+
 # hw/virtio-blk.c
 virtio_blk_req_complete(void *req, int status) "req %p status %d"
 virtio_blk_rw_complete(void *req, int ret) "req %p ret %d"
commit eeec61f291399115ba757421fd631e3414726f6f
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Wed Jan 18 14:40:43 2012 +0000

    block: add BlockJob interface for long-running operations
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index edfab49..2baac95 100644
--- a/block.c
+++ b/block.c
@@ -3858,3 +3858,51 @@ out:
 
     return ret;
 }
+
+void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs,
+                       BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockJob *job;
+
+    if (bs->job || bdrv_in_use(bs)) {
+        return NULL;
+    }
+    bdrv_set_in_use(bs, 1);
+
+    job = g_malloc0(job_type->instance_size);
+    job->job_type      = job_type;
+    job->bs            = bs;
+    job->cb            = cb;
+    job->opaque        = opaque;
+    bs->job = job;
+    return job;
+}
+
+void block_job_complete(BlockJob *job, int ret)
+{
+    BlockDriverState *bs = job->bs;
+
+    assert(bs->job == job);
+    job->cb(job->opaque, ret);
+    bs->job = NULL;
+    g_free(job);
+    bdrv_set_in_use(bs, 0);
+}
+
+int block_job_set_speed(BlockJob *job, int64_t value)
+{
+    if (!job->job_type->set_speed) {
+        return -ENOTSUP;
+    }
+    return job->job_type->set_speed(job, value);
+}
+
+void block_job_cancel(BlockJob *job)
+{
+    job->cancelled = true;
+}
+
+bool block_job_is_cancelled(BlockJob *job)
+{
+    return job->cancelled;
+}
diff --git a/block_int.h b/block_int.h
index 07d67ed..3566acb 100644
--- a/block_int.h
+++ b/block_int.h
@@ -69,6 +69,36 @@ typedef struct BlockIOBaseValue {
     uint64_t ios[2];
 } BlockIOBaseValue;
 
+typedef void BlockJobCancelFunc(void *opaque);
+typedef struct BlockJob BlockJob;
+typedef struct BlockJobType {
+    /** Derived BlockJob struct size */
+    size_t instance_size;
+
+    /** String describing the operation, part of query-block-jobs QMP API */
+    const char *job_type;
+
+    /** Optional callback for job types that support setting a speed limit */
+    int (*set_speed)(BlockJob *job, int64_t value);
+} BlockJobType;
+
+/**
+ * Long-running operation on a BlockDriverState
+ */
+struct BlockJob {
+    const BlockJobType *job_type;
+    BlockDriverState *bs;
+    bool cancelled;
+
+    /* These fields are published by the query-block-jobs QMP API */
+    int64_t offset;
+    int64_t len;
+    int64_t speed;
+
+    BlockDriverCompletionFunc *cb;
+    void *opaque;
+};
+
 struct BlockDriver {
     const char *format_name;
     int instance_size;
@@ -264,6 +294,9 @@ struct BlockDriverState {
     void *private;
 
     QLIST_HEAD(, BdrvTrackedRequest) tracked_requests;
+
+    /* long-running background operation */
+    BlockJob *job;
 };
 
 struct BlockDriverAIOCB {
@@ -287,4 +320,11 @@ void bdrv_set_io_limits(BlockDriverState *bs,
 int is_windows_drive(const char *filename);
 #endif
 
+void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs,
+                       BlockDriverCompletionFunc *cb, void *opaque);
+void block_job_complete(BlockJob *job, int ret);
+int block_job_set_speed(BlockJob *job, int64_t value);
+void block_job_cancel(BlockJob *job);
+bool block_job_is_cancelled(BlockJob *job);
+
 #endif /* BLOCK_INT_H */
commit 470c05047a09cda3de16bb3f98a130d9537357a4
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Wed Jan 18 14:40:42 2012 +0000

    block: make copy-on-read a per-request flag
    
    Previously copy-on-read could only be enabled for all requests to a
    block device.  This means requests coming from the guest as well as
    QEMU's internal requests would perform copy-on-read when enabled.
    
    For image streaming we want to support finer-grained behavior than just
    populating the image file from its backing image.  Image streaming
    supports partial streaming where a common backing image is preserved.
    In this case guest requests should not perform copy-on-read because they
    would indiscriminately copy data which should be left in a backing image
    from the backing chain.
    
    Introduce a per-request flag for copy-on-read so that a block device can
    process both regular and copy-on-read requests.  Overlapping reads and
    writes still need to be serialized for correctness when copy-on-read is
    happening, so add an in-flight reference count to track this.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 43f6484..edfab49 100644
--- a/block.c
+++ b/block.c
@@ -48,6 +48,10 @@
 
 #define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
 
+typedef enum {
+    BDRV_REQ_COPY_ON_READ = 0x1,
+} BdrvRequestFlags;
+
 static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
 static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
@@ -62,7 +66,8 @@ static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
                                          int64_t sector_num, int nb_sectors,
                                          QEMUIOVector *iov);
 static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
-    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
+    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
+    BdrvRequestFlags flags);
 static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
     int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
 static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
@@ -1292,7 +1297,7 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque)
 
     if (!rwco->is_write) {
         rwco->ret = bdrv_co_do_readv(rwco->bs, rwco->sector_num,
-                                     rwco->nb_sectors, rwco->qiov);
+                                     rwco->nb_sectors, rwco->qiov, 0);
     } else {
         rwco->ret = bdrv_co_do_writev(rwco->bs, rwco->sector_num,
                                       rwco->nb_sectors, rwco->qiov);
@@ -1500,7 +1505,7 @@ int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
     return 0;
 }
 
-static int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs,
+static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
 {
     /* Perform I/O through a temporary buffer so that users who scribble over
@@ -1523,8 +1528,8 @@ static int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs,
     round_to_clusters(bs, sector_num, nb_sectors,
                       &cluster_sector_num, &cluster_nb_sectors);
 
-    trace_bdrv_co_copy_on_readv(bs, sector_num, nb_sectors,
-                                cluster_sector_num, cluster_nb_sectors);
+    trace_bdrv_co_do_copy_on_readv(bs, sector_num, nb_sectors,
+                                   cluster_sector_num, cluster_nb_sectors);
 
     iov.iov_len = cluster_nb_sectors * BDRV_SECTOR_SIZE;
     iov.iov_base = bounce_buffer = qemu_blockalign(bs, iov.iov_len);
@@ -1559,7 +1564,8 @@ err:
  * Handle a read request in coroutine context
  */
 static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
-    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
+    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
+    BdrvRequestFlags flags)
 {
     BlockDriver *drv = bs->drv;
     BdrvTrackedRequest req;
@@ -1578,12 +1584,19 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
     }
 
     if (bs->copy_on_read) {
+        flags |= BDRV_REQ_COPY_ON_READ;
+    }
+    if (flags & BDRV_REQ_COPY_ON_READ) {
+        bs->copy_on_read_in_flight++;
+    }
+
+    if (bs->copy_on_read_in_flight) {
         wait_for_overlapping_requests(bs, sector_num, nb_sectors);
     }
 
     tracked_request_begin(&req, bs, sector_num, nb_sectors, false);
 
-    if (bs->copy_on_read) {
+    if (flags & BDRV_REQ_COPY_ON_READ) {
         int pnum;
 
         ret = bdrv_co_is_allocated(bs, sector_num, nb_sectors, &pnum);
@@ -1592,7 +1605,7 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
         }
 
         if (!ret || pnum != nb_sectors) {
-            ret = bdrv_co_copy_on_readv(bs, sector_num, nb_sectors, qiov);
+            ret = bdrv_co_do_copy_on_readv(bs, sector_num, nb_sectors, qiov);
             goto out;
         }
     }
@@ -1601,6 +1614,11 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
 
 out:
     tracked_request_end(&req);
+
+    if (flags & BDRV_REQ_COPY_ON_READ) {
+        bs->copy_on_read_in_flight--;
+    }
+
     return ret;
 }
 
@@ -1609,7 +1627,16 @@ int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
 {
     trace_bdrv_co_readv(bs, sector_num, nb_sectors);
 
-    return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov);
+    return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov, 0);
+}
+
+int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs,
+    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
+{
+    trace_bdrv_co_copy_on_readv(bs, sector_num, nb_sectors);
+
+    return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov,
+                            BDRV_REQ_COPY_ON_READ);
 }
 
 /*
@@ -1637,7 +1664,7 @@ static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
         bdrv_io_limits_intercept(bs, true, nb_sectors);
     }
 
-    if (bs->copy_on_read) {
+    if (bs->copy_on_read_in_flight) {
         wait_for_overlapping_requests(bs, sector_num, nb_sectors);
     }
 
@@ -3144,7 +3171,7 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque)
 
     if (!acb->is_write) {
         acb->req.error = bdrv_co_do_readv(bs, acb->req.sector,
-            acb->req.nb_sectors, acb->req.qiov);
+            acb->req.nb_sectors, acb->req.qiov, 0);
     } else {
         acb->req.error = bdrv_co_do_writev(bs, acb->req.sector,
             acb->req.nb_sectors, acb->req.qiov);
diff --git a/block.h b/block.h
index 3bd4398..a3b0b80 100644
--- a/block.h
+++ b/block.h
@@ -142,6 +142,8 @@ int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
     const void *buf, int count);
 int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
     int nb_sectors, QEMUIOVector *qiov);
+int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs,
+    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
 int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
     int nb_sectors, QEMUIOVector *qiov);
 int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t sector_num,
diff --git a/block_int.h b/block_int.h
index 311bd2a..07d67ed 100644
--- a/block_int.h
+++ b/block_int.h
@@ -218,6 +218,9 @@ struct BlockDriverState {
     BlockDriverState *backing_hd;
     BlockDriverState *file;
 
+    /* number of in-flight copy-on-read requests */
+    unsigned int copy_on_read_in_flight;
+
     /* async read/write emulation */
 
     void *sync_aiocb;
diff --git a/trace-events b/trace-events
index d2b0c61..035d08f 100644
--- a/trace-events
+++ b/trace-events
@@ -65,9 +65,10 @@ bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %
 bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
 bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
 bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
+bdrv_co_copy_on_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
 bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
 bdrv_co_io_em(void *bs, int64_t sector_num, int nb_sectors, int is_write, void *acb) "bs %p sector_num %"PRId64" nb_sectors %d is_write %d acb %p"
-bdrv_co_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t cluster_sector_num, int cluster_nb_sectors) "bs %p sector_num %"PRId64" nb_sectors %d cluster_sector_num %"PRId64" cluster_nb_sectors %d"
+bdrv_co_do_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t cluster_sector_num, int cluster_nb_sectors) "bs %p sector_num %"PRId64" nb_sectors %d cluster_sector_num %"PRId64" cluster_nb_sectors %d"
 
 # hw/virtio-blk.c
 virtio_blk_req_complete(void *req, int status) "req %p status %d"
commit 2d3735d3bf61d5c8e154a197a11535cc65044334
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Wed Jan 18 14:40:41 2012 +0000

    block: check bdrv_in_use() before blockdev operations
    
    Long-running block operations like block migration and image streaming
    must have continual access to their block device.  It is not safe to
    perform operations like hotplug, eject, change, resize, commit, or
    external snapshot while a long-running operation is in progress.
    
    This patch adds the missing bdrv_in_use() checks so that block migration
    and image streaming never have the rug pulled out from underneath them.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 3f072f6..43f6484 100644
--- a/block.c
+++ b/block.c
@@ -1020,6 +1020,10 @@ int bdrv_commit(BlockDriverState *bs)
         return -EACCES;
     }
 
+    if (bdrv_in_use(bs) || bdrv_in_use(bs->backing_hd)) {
+        return -EBUSY;
+    }
+
     backing_drv = bs->backing_hd->drv;
     ro = bs->backing_hd->read_only;
     strncpy(filename, bs->backing_hd->filename, sizeof(filename));
diff --git a/blockdev.c b/blockdev.c
index 1f83c88..0499ee6 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -592,12 +592,18 @@ void do_commit(Monitor *mon, const QDict *qdict)
     if (!strcmp(device, "all")) {
         bdrv_commit_all();
     } else {
+        int ret;
+
         bs = bdrv_find(device);
         if (!bs) {
             qerror_report(QERR_DEVICE_NOT_FOUND, device);
             return;
         }
-        bdrv_commit(bs);
+        ret = bdrv_commit(bs);
+        if (ret == -EBUSY) {
+            qerror_report(QERR_DEVICE_IN_USE, device);
+            return;
+        }
     }
 }
 
@@ -616,6 +622,10 @@ void qmp_blockdev_snapshot_sync(const char *device, const char *snapshot_file,
         error_set(errp, QERR_DEVICE_NOT_FOUND, device);
         return;
     }
+    if (bdrv_in_use(bs)) {
+        error_set(errp, QERR_DEVICE_IN_USE, device);
+        return;
+    }
 
     pstrcpy(old_filename, sizeof(old_filename), bs->filename);
 
@@ -667,6 +677,10 @@ void qmp_blockdev_snapshot_sync(const char *device, const char *snapshot_file,
 
 static void eject_device(BlockDriverState *bs, int force, Error **errp)
 {
+    if (bdrv_in_use(bs)) {
+        error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
+        return;
+    }
     if (!bdrv_dev_has_removable_media(bs)) {
         error_set(errp, QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
         return;
commit 7e6246670add62116729bd93811e41eb60f66b77
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Wed Jan 18 14:40:40 2012 +0000

    coroutine: add co_sleep_ns() coroutine sleep function
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/Makefile.objs b/Makefile.objs
index 9ca6063..48d1477 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -13,6 +13,7 @@ oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
 #######################################################################
 # coroutines
 coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o
+coroutine-obj-y += qemu-coroutine-sleep.o
 ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
 coroutine-obj-$(CONFIG_POSIX) += coroutine-ucontext.o
 else
diff --git a/qemu-coroutine-sleep.c b/qemu-coroutine-sleep.c
new file mode 100644
index 0000000..fd65274
--- /dev/null
+++ b/qemu-coroutine-sleep.c
@@ -0,0 +1,38 @@
+/*
+ * QEMU coroutine sleep
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Stefan Hajnoczi    <stefanha at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu-coroutine.h"
+#include "qemu-timer.h"
+
+typedef struct CoSleepCB {
+    QEMUTimer *ts;
+    Coroutine *co;
+} CoSleepCB;
+
+static void co_sleep_cb(void *opaque)
+{
+    CoSleepCB *sleep_cb = opaque;
+
+    qemu_free_timer(sleep_cb->ts);
+    qemu_coroutine_enter(sleep_cb->co, NULL);
+}
+
+void coroutine_fn co_sleep_ns(QEMUClock *clock, int64_t ns)
+{
+    CoSleepCB sleep_cb = {
+        .co = qemu_coroutine_self(),
+    };
+    sleep_cb.ts = qemu_new_timer(clock, SCALE_NS, co_sleep_cb, &sleep_cb);
+    qemu_mod_timer(sleep_cb.ts, qemu_get_clock_ns(clock) + ns);
+    qemu_coroutine_yield();
+}
diff --git a/qemu-coroutine.h b/qemu-coroutine.h
index 8a55fe1..34c15d4 100644
--- a/qemu-coroutine.h
+++ b/qemu-coroutine.h
@@ -17,6 +17,7 @@
 
 #include <stdbool.h>
 #include "qemu-queue.h"
+#include "qemu-timer.h"
 
 /**
  * Coroutines are a mechanism for stack switching and can be used for
@@ -199,4 +200,12 @@ void qemu_co_rwlock_wrlock(CoRwlock *lock);
  */
 void qemu_co_rwlock_unlock(CoRwlock *lock);
 
+/**
+ * Yield the coroutine for a given duration
+ *
+ * Note this function uses timers and hence only works when a main loop is in
+ * use.  See main-loop.h and do not use from qemu-tool programs.
+ */
+void coroutine_fn co_sleep_ns(QEMUClock *clock, int64_t ns);
+
 #endif /* QEMU_COROUTINE_H */
commit 031380d8770d2df6c386e4aeabd412007d3ebd54
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Mon Jan 16 09:28:06 2012 +0000

    block: replace unchecked strdup/malloc/calloc with glib
    
    Most of the codebase as been converted to use glib memory allocation
    functions.  There are still a few instances of malloc/calloc in the
    block layer and qemu-io.  Replace them, especially since they do not
    check the strdup/malloc/calloc return value.
    
    Reported-by: Dr David Alan Gilbert <davidagilbert at uk.ibm.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/blkdebug.c b/block/blkdebug.c
index 9b88535..a251802 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -292,10 +292,10 @@ static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
         return -EINVAL;
     }
 
-    config = strdup(filename);
+    config = g_strdup(filename);
     config[c - filename] = '\0';
     ret = read_config(s, config);
-    free(config);
+    g_free(config);
     if (ret < 0) {
         return ret;
     }
diff --git a/block/blkverify.c b/block/blkverify.c
index 4ca8584..9d5f1ec 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -87,10 +87,10 @@ static int blkverify_open(BlockDriverState *bs, const char *filename, int flags)
         return -EINVAL;
     }
 
-    raw = strdup(filename);
+    raw = g_strdup(filename);
     raw[c - filename] = '\0';
     ret = bdrv_file_open(&bs->file, raw, flags);
-    free(raw);
+    g_free(raw);
     if (ret < 0) {
         return ret;
     }
diff --git a/qemu-io.c b/qemu-io.c
index ffa62fb..7c446b6 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -130,7 +130,7 @@ static void print_report(const char *op, struct timeval *t, int64_t offset,
 static void *
 create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern)
 {
-    size_t *sizes = calloc(nr_iov, sizeof(size_t));
+    size_t *sizes = g_new0(size_t, nr_iov);
     size_t count = 0;
     void *buf = NULL;
     void *p;
@@ -172,7 +172,7 @@ create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern)
     }
 
 fail:
-    free(sizes);
+    g_free(sizes);
     return buf;
 }
 
@@ -471,14 +471,14 @@ static int read_f(int argc, char **argv)
     }
 
     if (Pflag) {
-        void *cmp_buf = malloc(pattern_count);
+        void *cmp_buf = g_malloc(pattern_count);
         memset(cmp_buf, pattern, pattern_count);
         if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
             printf("Pattern verification failed at offset %"
                    PRId64 ", %d bytes\n",
                    offset + pattern_offset, pattern_count);
         }
-        free(cmp_buf);
+        g_free(cmp_buf);
     }
 
     if (qflag) {
@@ -601,13 +601,13 @@ static int readv_f(int argc, char **argv)
     }
 
     if (Pflag) {
-        void *cmp_buf = malloc(qiov.size);
+        void *cmp_buf = g_malloc(qiov.size);
         memset(cmp_buf, pattern, qiov.size);
         if (memcmp(buf, cmp_buf, qiov.size)) {
             printf("Pattern verification failed at offset %"
                    PRId64 ", %zd bytes\n", offset, qiov.size);
         }
-        free(cmp_buf);
+        g_free(cmp_buf);
     }
 
     if (qflag) {
@@ -1063,7 +1063,7 @@ static void aio_write_done(void *opaque, int ret)
                  ctx->qiov.size, 1, ctx->Cflag);
 out:
     qemu_io_free(ctx->buf);
-    free(ctx);
+    g_free(ctx);
 }
 
 static void aio_read_done(void *opaque, int ret)
@@ -1079,14 +1079,14 @@ static void aio_read_done(void *opaque, int ret)
     }
 
     if (ctx->Pflag) {
-        void *cmp_buf = malloc(ctx->qiov.size);
+        void *cmp_buf = g_malloc(ctx->qiov.size);
 
         memset(cmp_buf, ctx->pattern, ctx->qiov.size);
         if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
             printf("Pattern verification failed at offset %"
                    PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size);
         }
-        free(cmp_buf);
+        g_free(cmp_buf);
     }
 
     if (ctx->qflag) {
@@ -1103,7 +1103,7 @@ static void aio_read_done(void *opaque, int ret)
                  ctx->qiov.size, 1, ctx->Cflag);
 out:
     qemu_io_free(ctx->buf);
-    free(ctx);
+    g_free(ctx);
 }
 
 static void aio_read_help(void)
@@ -1141,7 +1141,7 @@ static const cmdinfo_t aio_read_cmd = {
 static int aio_read_f(int argc, char **argv)
 {
     int nr_iov, c;
-    struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
+    struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
 
     while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
         switch (c) {
@@ -1152,7 +1152,7 @@ static int aio_read_f(int argc, char **argv)
             ctx->Pflag = 1;
             ctx->pattern = parse_pattern(optarg);
             if (ctx->pattern < 0) {
-                free(ctx);
+                g_free(ctx);
                 return 0;
             }
             break;
@@ -1163,20 +1163,20 @@ static int aio_read_f(int argc, char **argv)
             ctx->vflag = 1;
             break;
         default:
-            free(ctx);
+            g_free(ctx);
             return command_usage(&aio_read_cmd);
         }
     }
 
     if (optind > argc - 2) {
-        free(ctx);
+        g_free(ctx);
         return command_usage(&aio_read_cmd);
     }
 
     ctx->offset = cvtnum(argv[optind]);
     if (ctx->offset < 0) {
         printf("non-numeric length argument -- %s\n", argv[optind]);
-        free(ctx);
+        g_free(ctx);
         return 0;
     }
     optind++;
@@ -1184,14 +1184,14 @@ static int aio_read_f(int argc, char **argv)
     if (ctx->offset & 0x1ff) {
         printf("offset %" PRId64 " is not sector aligned\n",
                ctx->offset);
-        free(ctx);
+        g_free(ctx);
         return 0;
     }
 
     nr_iov = argc - optind;
     ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab);
     if (ctx->buf == NULL) {
-        free(ctx);
+        g_free(ctx);
         return 0;
     }
 
@@ -1237,7 +1237,7 @@ static int aio_write_f(int argc, char **argv)
 {
     int nr_iov, c;
     int pattern = 0xcd;
-    struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
+    struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
 
     while ((c = getopt(argc, argv, "CqP:")) != EOF) {
         switch (c) {
@@ -1250,25 +1250,25 @@ static int aio_write_f(int argc, char **argv)
         case 'P':
             pattern = parse_pattern(optarg);
             if (pattern < 0) {
-                free(ctx);
+                g_free(ctx);
                 return 0;
             }
             break;
         default:
-            free(ctx);
+            g_free(ctx);
             return command_usage(&aio_write_cmd);
         }
     }
 
     if (optind > argc - 2) {
-        free(ctx);
+        g_free(ctx);
         return command_usage(&aio_write_cmd);
     }
 
     ctx->offset = cvtnum(argv[optind]);
     if (ctx->offset < 0) {
         printf("non-numeric length argument -- %s\n", argv[optind]);
-        free(ctx);
+        g_free(ctx);
         return 0;
     }
     optind++;
@@ -1276,14 +1276,14 @@ static int aio_write_f(int argc, char **argv)
     if (ctx->offset & 0x1ff) {
         printf("offset %" PRId64 " is not sector aligned\n",
                ctx->offset);
-        free(ctx);
+        g_free(ctx);
         return 0;
     }
 
     nr_iov = argc - optind;
     ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern);
     if (ctx->buf == NULL) {
-        free(ctx);
+        g_free(ctx);
         return 0;
     }
 
commit bd6032470631d8d5de6db84ecb55398b70d9d2f3
Author: Gregory Farnum <gregory.farnum at dreamhost.com>
Date:   Wed Jan 11 11:53:52 2012 -0800

    rbd: wire up snapshot removal and rollback functionality
    
    Signed-off-by: Greg Farnum <gregory.farnum at dreamhost.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/rbd.c b/block/rbd.c
index db5abf2..46a8579 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -789,6 +789,26 @@ static int qemu_rbd_snap_create(BlockDriverState *bs,
     return 0;
 }
 
+static int qemu_rbd_snap_remove(BlockDriverState *bs,
+                                const char *snapshot_name)
+{
+    BDRVRBDState *s = bs->opaque;
+    int r;
+
+    r = rbd_snap_remove(s->image, snapshot_name);
+    return r;
+}
+
+static int qemu_rbd_snap_rollback(BlockDriverState *bs,
+                                  const char *snapshot_name)
+{
+    BDRVRBDState *s = bs->opaque;
+    int r;
+
+    r = rbd_snap_rollback(s->image, snapshot_name);
+    return r;
+}
+
 static int qemu_rbd_snap_list(BlockDriverState *bs,
                               QEMUSnapshotInfo **psn_tab)
 {
@@ -862,7 +882,9 @@ static BlockDriver bdrv_rbd = {
     .bdrv_co_flush_to_disk  = qemu_rbd_co_flush,
 
     .bdrv_snapshot_create   = qemu_rbd_snap_create,
+    .bdrv_snapshot_delete   = qemu_rbd_snap_remove,
     .bdrv_snapshot_list     = qemu_rbd_snap_list,
+    .bdrv_snapshot_goto     = qemu_rbd_snap_rollback,
 };
 
 static void bdrv_rbd_init(void)
commit 331636431af32ece373f4b1fb7c3ae9d0615e2a6
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Oct 9 09:58:00 2011 +0000

    vga: compile cirrus_vga in hwlib
    
    Remove target dependencies and compile Cirrus VGA in hwlib.
    
    Address masking can be removed since memory API handles that now.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/Makefile.objs b/Makefile.objs
index 04a1d1b..9ca6063 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -289,6 +289,7 @@ hw-obj-$(CONFIG_VGA_ISA) += vga-isa.o
 hw-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
 hw-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
 hw-obj-$(CONFIG_VMMOUSE) += vmmouse.o
+hw-obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o
 
 hw-obj-$(CONFIG_RC4030) += rc4030.o
 hw-obj-$(CONFIG_DP8393X) += dp8393x.o
diff --git a/Makefile.target b/Makefile.target
index 69193d4..e554d33 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -197,7 +197,6 @@ obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
 obj-$(CONFIG_KVM) += kvm.o kvm-all.o
 obj-$(CONFIG_NO_KVM) += kvm-stub.o
 obj-$(CONFIG_VGA) += vga.o
-obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o
 obj-y += memory.o savevm.o
 LIBS+=-lz
 
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index a031079..7ce35ec 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -618,7 +618,6 @@ 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;
         memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur);
 	off_begin += off_pitch;
     }
@@ -1897,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,
commit fd4aa979033ca604ad829cf95055d4b5c5ed1063
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Oct 16 16:04:59 2011 +0000

    memory: change dirty setting APIs to take a size
    
    Instead of each target knowing or guessing the guest page size,
    just pass the desired size of dirtied memory area.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/arch_init.c b/arch_init.c
index 95ac682..2366511 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -285,7 +285,7 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
             for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
                 if (!memory_region_get_dirty(block->mr, addr,
                                              DIRTY_MEMORY_MIGRATION)) {
-                    memory_region_set_dirty(block->mr, addr);
+                    memory_region_set_dirty(block->mr, addr, TARGET_PAGE_SIZE);
                 }
             }
         }
diff --git a/exec-obsolete.h b/exec-obsolete.h
index 22e0ba5..03cf35e 100644
--- a/exec-obsolete.h
+++ b/exec-obsolete.h
@@ -76,6 +76,20 @@ static inline int cpu_physical_memory_set_dirty_flags(ram_addr_t addr,
     return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] |= dirty_flags;
 }
 
+static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start,
+                                                       ram_addr_t length,
+                                                       int dirty_flags)
+{
+    uint8_t *p;
+    ram_addr_t addr, end;
+
+    end = start + length;
+    p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
+    for (addr = start; addr <= end; addr += TARGET_PAGE_SIZE) {
+        *p++ |= dirty_flags;
+    }
+}
+
 static inline void cpu_physical_memory_mask_dirty_range(ram_addr_t start,
                                                         ram_addr_t length,
                                                         int dirty_flags)
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 8506bb5..a031079 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -619,10 +619,7 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
 	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;
     }
 }
@@ -1923,8 +1920,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,
@@ -1948,8 +1944,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);
 }
 
 /***************************************
@@ -2039,7 +2034,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,
@@ -2311,7 +2307,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);
diff --git a/hw/g364fb.c b/hw/g364fb.c
index 33ec149..02ec7b5 100644
--- a/hw/g364fb.c
+++ b/hw/g364fb.c
@@ -268,12 +268,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 +382,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 +390,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,
diff --git a/hw/qxl.c b/hw/qxl.c
index bdd36f9..6442193 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)
diff --git a/hw/tcx.c b/hw/tcx.c
index 75a28f2..b6a2753 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)
diff --git a/hw/vga.c b/hw/vga.c
index 950f97e..4dc2610 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -854,7 +854,7 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
             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) {
         /* odd/even mode (aka text mode mapping) */
@@ -867,7 +867,7 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
             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 */
@@ -941,7 +941,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));
     }
 }
 
diff --git a/hw/vhost.c b/hw/vhost.c
index 4778521..5ece659 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/kvm-all.c b/kvm-all.c
index e411d3c..7d4e544 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -368,7 +368,7 @@ static int kvm_get_dirty_pages_log_range(MemoryRegionSection *section,
                 page_number = i * HOST_LONG_BITS + j;
                 addr1 = page_number * TARGET_PAGE_SIZE;
                 addr = section->offset_within_region + addr1;
-                memory_region_set_dirty(section->mr, addr);
+                memory_region_set_dirty(section->mr, addr, TARGET_PAGE_SIZE);
             } while (c != 0);
         }
     }
@@ -379,8 +379,9 @@ static int kvm_get_dirty_pages_log_range(MemoryRegionSection *section,
 
 /**
  * kvm_physical_sync_dirty_bitmap - Grab dirty bitmap from kernel space
- * This function updates qemu's dirty bitmap using cpu_physical_memory_set_dirty().
- * This means all bits are set to dirty.
+ * This function updates qemu's dirty bitmap using
+ * memory_region_set_dirty().  This means all bits are set
+ * to dirty.
  *
  * @start_add: start of logged region.
  * @end_addr: end of logged region.
diff --git a/memory.c b/memory.c
index 68e5cdf..ee4c98a 100644
--- a/memory.c
+++ b/memory.c
@@ -1142,10 +1142,11 @@ bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
     return cpu_physical_memory_get_dirty(mr->ram_addr + addr, 1 << client);
 }
 
-void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr)
+void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr,
+                             target_phys_addr_t size)
 {
     assert(mr->terminates);
-    return cpu_physical_memory_set_dirty(mr->ram_addr + addr);
+    return cpu_physical_memory_set_dirty_range(mr->ram_addr + addr, size, -1);
 }
 
 void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
diff --git a/memory.h b/memory.h
index 34c69cf..fa45b99 100644
--- a/memory.h
+++ b/memory.h
@@ -396,14 +396,17 @@ bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
                              unsigned client);
 
 /**
- * memory_region_set_dirty: Mark a page as dirty in a memory region.
+ * memory_region_set_dirty: Mark a range of bytes as dirty in a memory region.
  *
- * Marks a page as dirty, after it has been dirtied outside guest code.
+ * Marks a range of bytes as dirty, after it has been dirtied outside
+ * guest code.
  *
- * @mr: the memory region being queried.
+ * @mr: the memory region being dirtied.
  * @addr: the address (relative to the start of the region) being dirtied.
+ * @size: size of the range being dirtied.
  */
-void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr);
+void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr,
+                             target_phys_addr_t size);
 
 /**
  * memory_region_sync_dirty_bitmap: Synchronize a region's dirty bitmap with
diff --git a/xen-all.c b/xen-all.c
index d1fc597..fd39168 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -447,7 +447,8 @@ static void xen_sync_dirty_bitmap(XenIOState *state,
             j = ffsl(map) - 1;
             map &= ~(1ul << j);
             memory_region_set_dirty(framebuffer,
-                                    (i * width + j) * TARGET_PAGE_SIZE);
+                                    (i * width + j) * TARGET_PAGE_SIZE,
+                                    TARGET_PAGE_SIZE);
         };
     }
 }
commit 59abb06198ee9471e29c970f294eae80c0b39be1
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Jan 22 11:00:44 2012 +0000

    memory: fix dirty mask function length handling
    
    Fix handling of cases like start = 0xfff, length = 2.
    
    Change length to ram_addr_t to handle larger lengths.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/exec-obsolete.h b/exec-obsolete.h
index c412be9..22e0ba5 100644
--- a/exec-obsolete.h
+++ b/exec-obsolete.h
@@ -77,17 +77,18 @@ static inline int cpu_physical_memory_set_dirty_flags(ram_addr_t addr,
 }
 
 static inline void cpu_physical_memory_mask_dirty_range(ram_addr_t start,
-                                                        int length,
+                                                        ram_addr_t length,
                                                         int dirty_flags)
 {
-    int i, mask, len;
+    int mask;
     uint8_t *p;
+    ram_addr_t addr, end;
 
-    len = length >> TARGET_PAGE_BITS;
+    end = start + length;
     mask = ~dirty_flags;
     p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
-    for (i = 0; i < len; i++) {
-        p[i] &= mask;
+    for (addr = start; addr <= end; addr += TARGET_PAGE_SIZE) {
+        *p++ &= mask;
     }
 }
 
commit c5bd4f3d2ddf243565d94a5a16eafcb994c1524a
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Tue Jan 24 17:27:35 2012 +0000

    vga: fix -nodefaults -device VGA
    
    Flag -nodefaults should also imply no VGA. This was broken in
    a369da5f31ddbdeb32a7f76622e480d3995fbb00.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/vl.c b/vl.c
index 57378b6..d88a18c 100644
--- a/vl.c
+++ b/vl.c
@@ -3006,6 +3006,7 @@ int main(int argc, char **argv, char **envp)
                 default_floppy = 0;
                 default_cdrom = 0;
                 default_sdcard = 0;
+                vga_model = "none";
                 break;
             case QEMU_OPTION_xen_domid:
                 if (!(xen_available())) {
commit 0b03bdfca179f87c2256c61ee908011890f9d4df
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Jan 25 12:42:29 2012 +0000

    Add Cortex-A15 CPU definition
    
    Add a definition of a Cortex-A15 CPU. Note that for the moment we do
    not implement any of:
     * Large Physical Address Extensions (LPAE)
     * Virtualization Extensions
     * Generic Timer
     * TrustZone (this is also true of our existing Cortex-A9 model, etc)
    
    This CPU model is sufficient to boot a Linux kernel which has been
    compiled for an A15 without LPAE enabled.
    
    Reviewed-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 7442c99..0d9b39c 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -433,6 +433,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
 #define ARM_CPUID_ARM11MPCORE 0x410fb022
 #define ARM_CPUID_CORTEXA8    0x410fc080
 #define ARM_CPUID_CORTEXA9    0x410fc090
+#define ARM_CPUID_CORTEXA15   0x412fc0f1
 #define ARM_CPUID_CORTEXM3    0x410fc231
 #define ARM_CPUID_ANY         0xffffffff
 
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 5e7205a..ea4f35f 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -10,6 +10,16 @@
 #if !defined(CONFIG_USER_ONLY)
 #include "hw/loader.h"
 #endif
+#include "sysemu.h"
+
+static uint32_t cortexa15_cp15_c0_c1[8] = {
+    0x00001131, 0x00011011, 0x02010555, 0x00000000,
+    0x10201105, 0x20000000, 0x01240000, 0x02102211
+};
+
+static uint32_t cortexa15_cp15_c0_c2[8] = {
+    0x02101110, 0x13112111, 0x21232041, 0x11112131, 0x10011142, 0, 0, 0
+};
 
 static uint32_t cortexa9_cp15_c0_c1[8] =
 { 0x1031, 0x11, 0x000, 0, 0x00100103, 0x20000000, 0x01230000, 0x00002111 };
@@ -158,6 +168,27 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */
         env->cp15.c1_sys = 0x00c50078;
         break;
+    case ARM_CPUID_CORTEXA15:
+        set_feature(env, ARM_FEATURE_V7);
+        set_feature(env, ARM_FEATURE_VFP4);
+        set_feature(env, ARM_FEATURE_VFP_FP16);
+        set_feature(env, ARM_FEATURE_NEON);
+        set_feature(env, ARM_FEATURE_THUMB2EE);
+        set_feature(env, ARM_FEATURE_ARM_DIV);
+        set_feature(env, ARM_FEATURE_V7MP);
+        set_feature(env, ARM_FEATURE_GENERIC_TIMER);
+        env->vfp.xregs[ARM_VFP_FPSID] = 0x410430f0;
+        env->vfp.xregs[ARM_VFP_MVFR0] = 0x10110222;
+        env->vfp.xregs[ARM_VFP_MVFR1] = 0x11111111;
+        memcpy(env->cp15.c0_c1, cortexa15_cp15_c0_c1, 8 * sizeof(uint32_t));
+        memcpy(env->cp15.c0_c2, cortexa15_cp15_c0_c2, 8 * sizeof(uint32_t));
+        env->cp15.c0_cachetype = 0x8444c004;
+        env->cp15.c0_clid = 0x0a200023;
+        env->cp15.c0_ccsid[0] = 0x701fe00a; /* 32K L1 dcache */
+        env->cp15.c0_ccsid[1] = 0x201fe00a; /* 32K L1 icache */
+        env->cp15.c0_ccsid[2] = 0x711fe07a; /* 4096K L2 unified cache */
+        env->cp15.c1_sys = 0x00c50078;
+        break;
     case ARM_CPUID_CORTEXM3:
         set_feature(env, ARM_FEATURE_V7);
         set_feature(env, ARM_FEATURE_M);
@@ -416,6 +447,7 @@ static const struct arm_cpu_t arm_cpu_names[] = {
     { ARM_CPUID_CORTEXM3, "cortex-m3"},
     { ARM_CPUID_CORTEXA8, "cortex-a8"},
     { ARM_CPUID_CORTEXA9, "cortex-a9"},
+    { ARM_CPUID_CORTEXA15, "cortex-a15" },
     { ARM_CPUID_TI925T, "ti925t" },
     { ARM_CPUID_PXA250, "pxa250" },
     { ARM_CPUID_SA1100,    "sa1100" },
@@ -670,8 +702,6 @@ uint32_t HELPER(get_r13_banked)(CPUState *env, uint32_t mode)
 
 #else
 
-extern int semihosting_enabled;
-
 /* Map CPU modes onto saved register banks.  */
 static inline int bank_number(CPUState *env, int mode)
 {
@@ -1945,6 +1975,7 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
             case ARM_CPUID_CORTEXA8:
                 return 2;
             case ARM_CPUID_CORTEXA9:
+            case ARM_CPUID_CORTEXA15:
                 return 0;
             default:
                 goto bad_reg;
@@ -2065,11 +2096,26 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
                     goto bad_reg;
                 }
             case 1: /* L2 cache */
-                if (crm != 0) {
+                /* L2 Lockdown and Auxiliary control.  */
+                switch (op2) {
+                case 0:
+                    /* L2 cache lockdown (A8 only) */
+                    return 0;
+                case 2:
+                    /* L2 cache auxiliary control (A8) or control (A15) */
+                    if (ARM_CPUID(env) == ARM_CPUID_CORTEXA15) {
+                        /* Linux wants the number of processors from here.
+                         * Might as well set the interrupt-controller bit too.
+                         */
+                        return ((smp_cpus - 1) << 24) | (1 << 23);
+                    }
+                    return 0;
+                case 3:
+                    /* L2 cache extended control (A15) */
+                    return 0;
+                default:
                     goto bad_reg;
                 }
-                /* L2 Lockdown and Auxiliary control.  */
-                return 0;
             default:
                 goto bad_reg;
             }
commit 0383ac006f6bfa60d5cb3d0ddf4a9e1d65f9c900
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Jan 25 12:42:29 2012 +0000

    Add dummy implementation of generic timer cp15 registers
    
    Add a dummy implementation of the cp15 registers for the generic
    timer (found in the Cortex-A15), just sufficient for Linux to
    decide that it can't use it. This requires at least CNTP_CTL and
    CNTFRQ to be implemented as RAZ/WI; we RAZ/WI all of c14.
    
    Reviewed-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 42c53a7..7442c99 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -382,6 +382,7 @@ enum arm_features {
     ARM_FEATURE_VAPA, /* cp15 VA to PA lookups */
     ARM_FEATURE_ARM_DIV, /* divide supported in ARM encoding */
     ARM_FEATURE_VFP4, /* VFPv4 (implies that NEON is v2) */
+    ARM_FEATURE_GENERIC_TIMER,
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 22e40fc..5e7205a 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1764,7 +1764,11 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
             goto bad_reg;
         }
         break;
-    case 14: /* Reserved.  */
+    case 14: /* Generic timer */
+        if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) {
+            /* Dummy implementation: RAZ/WI for all */
+            break;
+        }
         goto bad_reg;
     case 15: /* Implementation specific.  */
         if (arm_feature(env, ARM_FEATURE_XSCALE)) {
@@ -2134,7 +2138,11 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
         default:
             goto bad_reg;
         }
-    case 14: /* Reserved.  */
+    case 14: /* Generic timer */
+        if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) {
+            /* Dummy implementation: RAZ/WI for all */
+            return 0;
+        }
         goto bad_reg;
     case 15: /* Implementation specific.  */
         if (arm_feature(env, ARM_FEATURE_XSCALE)) {
commit 5fe91019e66e2c2187f0af2324e25d450eb03a86
Author: Mark Langsdorf <mark.langsdorf at calxeda.com>
Date:   Wed Jan 25 11:49:46 2012 +0000

    arm: store the config_base_register during cpu_reset
    
    Long term, the config_base_register will be a QDM parameter. In the
    meantime, models that use it need to be able to preserve it across
    cpu_reset() calls.
    
    Signed-off-by: Mark Langsdorf <mark.langsdorf at calxeda.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index f6e998b..22e40fc 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -255,6 +255,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
 void cpu_reset(CPUARMState *env)
 {
     uint32_t id;
+    uint32_t tmp = 0;
 
     if (qemu_loglevel_mask(CPU_LOG_RESET)) {
         qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
@@ -262,9 +263,11 @@ void cpu_reset(CPUARMState *env)
     }
 
     id = env->cp15.c0_cpuid;
+    tmp = env->cp15.c15_config_base_address;
     memset(env, 0, offsetof(CPUARMState, breakpoints));
     if (id)
         cpu_reset_model_id(env, id);
+    env->cp15.c15_config_base_address = tmp;
 #if defined (CONFIG_USER_ONLY)
     env->uncached_cpsr = ARM_CPU_MODE_USR;
     /* For user mode we must enable access to coprocessors */
commit 85836979052a64f3d866057e3abc9c7792a7fdf0
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Jan 25 11:49:46 2012 +0000

    target-arm/helper.c: Don't assume softfloat int32 is 32 bits only
    
    In the helper routines for VCVT float-to-int conversions, add
    an explicit cast rather than relying on the softfloat int32
    type being exactly 32 bits wide (which it is not guaranteed to be).
    Without this, if the softfloat type was 64 bits wide we would
    get zero-extension of the 32 bit value from the ARM register
    rather than sign-extension, since TCG i32 values are passed as
    uint32_t.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index f11279e..f6e998b 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2785,7 +2785,7 @@ DO_VFP_cmp(d, float64)
     float##fsz HELPER(name)(uint32_t x, void *fpstp) \
 { \
     float_status *fpst = fpstp; \
-    return sign##int32_to_##float##fsz(x, fpst); \
+    return sign##int32_to_##float##fsz((sign##int32_t)x, fpst); \
 }
 
 #define CONV_FTOI(name, fsz, sign, round) \
commit dc8714ca57c1796abddf7c96d6f66852a972cb08
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Jan 25 11:49:46 2012 +0000

    target-arm: Fix implementation of TLB invalidate operations
    
    Fix some bugs in the implementation of the TLB invalidate
    operations on ARM:
     * the 'invalidate all' op was not passing flush_global=1
       to tlb_flush(); this doesn't have a practical effect since
       tlb_flush() currently ignores that argument, but is
       semantically incorrect
     * 'invalidate by address for all ASIDs' was implemented as
       flushing the whole TLB, which invalidates much more than
       strictly necessary. Use tlb_flush_page() instead.
    We also annotate the ops with the ARM ARM official acronyms.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 00458fc..f11279e 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1610,18 +1610,17 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
         break;
     case 8: /* MMU TLB control.  */
         switch (op2) {
-        case 0: /* Invalidate all.  */
-            tlb_flush(env, 0);
+        case 0: /* Invalidate all (TLBIALL) */
+            tlb_flush(env, 1);
             break;
-        case 1: /* Invalidate single TLB entry.  */
+        case 1: /* Invalidate single TLB entry by MVA and ASID (TLBIMVA) */
             tlb_flush_page(env, val & TARGET_PAGE_MASK);
             break;
-        case 2: /* Invalidate on ASID.  */
+        case 2: /* Invalidate by ASID (TLBIASID) */
             tlb_flush(env, val == 0);
             break;
-        case 3: /* Invalidate single entry on MVA.  */
-            /* ??? This is like case 1, but ignores ASID.  */
-            tlb_flush(env, 1);
+        case 3: /* Invalidate single entry by MVA, all ASIDs (TLBIMVAA) */
+            tlb_flush_page(env, val & TARGET_PAGE_MASK);
             break;
         default:
             goto bad_reg;
commit 61eb1f38c10ef73220e862313b792c56646495a6
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Mon Jan 23 19:59:14 2012 +0000

    hyperv: fix build on non-KVM hosts
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/Makefile.target b/Makefile.target
index 092565a..69193d4 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -201,7 +201,7 @@ obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o
 obj-y += memory.o savevm.o
 LIBS+=-lz
 
-obj-i386-y +=hyperv.o
+obj-i386-$(CONFIG_KVM) += hyperv.o
 
 QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
diff --git a/target-i386/hyperv.h b/target-i386/hyperv.h
index 15467bf..bacb1d4 100644
--- a/target-i386/hyperv.h
+++ b/target-i386/hyperv.h
@@ -14,7 +14,9 @@
 #define QEMU_HW_HYPERV_H 1
 
 #include "qemu-common.h"
+#ifdef CONFIG_KVM
 #include <asm/hyperv.h>
+#endif
 
 #ifndef HYPERV_SPINLOCK_NEVER_RETRY
 #define HYPERV_SPINLOCK_NEVER_RETRY             0xFFFFFFFF
@@ -24,7 +26,7 @@
 #define KVM_CPUID_SIGNATURE_NEXT                0x40000100
 #endif
 
-#ifndef CONFIG_USER_ONLY
+#if !defined(CONFIG_USER_ONLY) && defined(CONFIG_KVM)
 void hyperv_enable_vapic_recommended(bool val);
 void hyperv_enable_relaxed_timing(bool val);
 void hyperv_set_spinlock_retries(int val);
commit 5b4448d27d7c6ff6e18a1edc8245cb1db783e37c
Merge: c4ccbea... 6a48ffa...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Jan 23 11:00:26 2012 -0600

    Merge remote-tracking branch 'qemu-kvm/uq/master' into staging
    
    * qemu-kvm/uq/master:
      kvm: Activate in-kernel irqchip support
      kvm: x86: Add user space part for in-kernel IOAPIC
      kvm: x86: Add user space part for in-kernel i8259
      kvm: x86: Add user space part for in-kernel APIC
      kvm: x86: Establish IRQ0 override control
      kvm: Introduce core services for in-kernel irqchip support
      memory: Introduce memory_region_init_reservation
      ioapic: Factor out base class for KVM reuse
      ioapic: Drop post-load irr initialization
      i8259: Factor out base class for KVM reuse
      i8259: Completely privatize PicState
      apic: Open-code timer save/restore
      apic: Factor out base class for KVM reuse
      apic: Introduce apic_report_irq_delivered
      apic: Inject external NMI events via LINT1
      apic: Stop timer on reset
      kvm: Move kvmclock into hw/kvm folder
      msi: Generalize msix_supported to msi_supported
      hyper-v: initialize Hyper-V CPUID leaves.
      hyper-v: introduce Hyper-V support infrastructure.
    
    Conflicts:
    	Makefile.target
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --cc Makefile.target
index bb18d72,98cb997..092565a
--- a/Makefile.target
+++ b/Makefile.target
@@@ -226,8 -226,9 +228,8 @@@ obj-$(CONFIG_IVSHMEM) += ivshmem.
  obj-y += device-hotplug.o
  
  # Hardware support
 -obj-i386-y += vga.o
  obj-i386-y += mc146818rtc.o pc.o
- obj-i386-y += sga.o apic.o ioapic.o piix_pci.o
 -obj-i386-y += cirrus_vga.o sga.o apic_common.o apic.o ioapic_common.o ioapic.o piix_pci.o
++obj-i386-y += sga.o apic_common.o apic.o ioapic_common.o ioapic.o piix_pci.o
  obj-i386-y += vmport.o
  obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o
  obj-i386-y += debugcon.o multiboot.o
commit c4ccbeaca521bdbf5cb8db37dc67c47e1add0586
Merge: 65f82df... 506b7dd...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Jan 23 10:58:02 2012 -0600

    Merge remote-tracking branch 'afaerber/prep-up' into staging
    
    * afaerber/prep-up:
      prep: Use i82378 PCI->ISA bridge for 'prep' machine
      prep: Add i82378 PCI-to-ISA bridge emulation
      prep: Add i82374 DMA emulation
      MAINTAINERS: Add PCI host bridge files to PReP machine
      prep: qdev'ify Raven host bridge (SysBus)
      prep_pci: Update I/O to MemoryRegion ops
      prep_pci: Simplify I/O endianness
      prep: qdev'ify Raven host bridge (PCIDevice)
      prep: Use ISA m48t59
      prep: Fix offset of BIOS MemoryRegion

diff --cc MAINTAINERS
index 87237a6,148f0d2..73c0a10
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@@ -312,9 -305,9 +312,10 @@@ F: hw/grackle_pci.
  
  PReP
  M: Andreas Färber <andreas.faerber at web.de>
 +L: qemu-ppc at nongnu.org
  S: Odd Fixes
  F: hw/ppc_prep.c
+ F: hw/prep_pci.[hc]
  
  SH4 Machines
  ------------
commit 65f82df0d7a71ce1b10cd4c5ab08888d176ac840
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Jan 23 07:30:43 2012 -0600

    e1000: bounds packet size against buffer size
    
    Otherwise we can write beyond the buffer and corrupt memory.  This is tracked
    as CVE-2012-0029.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/e1000.c b/hw/e1000.c
index a29c944..86c5416 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;
     }
commit 520c0d8d2772ccc9f9275bd934e13ec9b15774e4
Author: Andreas Färber <afaerber at suse.de>
Date:   Mon Jan 16 01:46:51 2012 +0100

    target-sparc: Fix mixup of uint64 and uint64_t
    
    Commit 793a137a41ad4125011c7022cf16a1baa40a5ab6 (target-sparc:
    Implement BMASK/BSHUFFLE.) introduced a stray usage of softfloat uint64
    type.
    
    Use uint64_t instead.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Cc: Richard Henderson <rth at twiddle.net>
    Cc: Blue Swirl <blauwirbel at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c
index a992c29..9d2edb0 100644
--- a/target-sparc/vis_helper.c
+++ b/target-sparc/vis_helper.c
@@ -459,7 +459,7 @@ uint32_t helper_fpackfix(uint64_t gsr, uint64_t rs2)
     return ret;
 }
 
-uint64 helper_bshuffle(uint64_t gsr, uint64_t src1, uint64_t src2)
+uint64_t helper_bshuffle(uint64_t gsr, uint64_t src1, uint64_t src2)
 {
     union {
         uint64_t ll[2];
commit 6618f9095c798aff32ce0ca1313dcdc17677745c
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Oct 23 14:39:46 2011 +0000

    sga: fix copypasta
    
    Fix the name of the init function.
    
    Reviewed-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/sga.c b/hw/sga.c
index 7ef750a..ea11937 100644
--- a/hw/sga.c
+++ b/hw/sga.c
@@ -35,7 +35,7 @@ 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;
@@ -45,7 +45,7 @@ static ISADeviceInfo sga_info = {
     .qdev.name    = "sga",
     .qdev.desc    = "Serial Graphics Adapter",
     .qdev.size    = sizeof(ISASGAState),
-    .init         = isa_cirrus_vga_initfn,
+    .init         = sga_initfn,
 };
 
 static void sga_register(void)
commit 3d402831de14d9e23ed8efcfdf81b01a53472fe2
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Oct 1 16:33:43 2011 +0000

    vga: make Cirrus ISA device optional
    
    Reviewed-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/Makefile.target b/Makefile.target
index a67e1fe..bb18d72 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -196,6 +196,8 @@ obj-$(CONFIG_VHOST_NET) += vhost.o
 obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
 obj-$(CONFIG_KVM) += kvm.o kvm-all.o
 obj-$(CONFIG_NO_KVM) += kvm-stub.o
+obj-$(CONFIG_VGA) += vga.o
+obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o
 obj-y += memory.o savevm.o
 LIBS+=-lz
 
@@ -224,9 +226,8 @@ obj-$(CONFIG_IVSHMEM) += ivshmem.o
 obj-y += device-hotplug.o
 
 # Hardware support
-obj-i386-y += vga.o
 obj-i386-y += mc146818rtc.o pc.o
-obj-i386-y += cirrus_vga.o sga.o apic.o ioapic.o piix_pci.o
+obj-i386-y += sga.o apic.o ioapic.o piix_pci.o
 obj-i386-y += vmport.o
 obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
@@ -236,7 +237,6 @@ obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
 obj-ppc-y = ppc.o ppc_booke.o
-obj-ppc-y += vga.o
 # PREP target
 obj-ppc-y += mc146818rtc.o
 obj-ppc-y += ppc_prep.o
@@ -290,10 +290,8 @@ obj-lm32-y += framebuffer.o
 
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
-obj-mips-y += vga.o
 obj-mips-y += jazz_led.o
 obj-mips-y += gt64xxx.o mc146818rtc.o
-obj-mips-y += cirrus_vga.o
 obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o
 
 obj-microblaze-y = petalogix_s3adsp1800_mmu.o
@@ -323,9 +321,7 @@ obj-cris-y += etraxfs_ser.o
 
 ifeq ($(TARGET_ARCH), sparc64)
 obj-sparc-y = sun4u.o apb_pci.o
-obj-sparc-y += vga.o
 obj-sparc-y += mc146818rtc.o
-obj-sparc-y += cirrus_vga.o
 else
 obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o
 obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o
@@ -353,7 +349,7 @@ obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \
 obj-arm-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \
 		omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o
 obj-arm-y += omap_sx1.o palm.o tsc210x.o
-obj-arm-y += nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
+obj-arm-y += nseries.o blizzard.o onenand.o cbus.o tusb6010.o usb-musb.o
 obj-arm-y += mst_fpga.o mainstone.o
 obj-arm-y += z2.o
 obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
@@ -373,7 +369,6 @@ obj-m68k-y += m68k-semi.o dummy_m68k.o
 obj-s390x-y = s390-virtio-bus.o s390-virtio.o
 
 obj-alpha-y = mc146818rtc.o
-obj-alpha-y += vga.o cirrus_vga.o
 obj-alpha-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o
 
 obj-xtensa-y += xtensa_pic.o
diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak
index bd1dd95..501dd41 100644
--- a/default-configs/alpha-softmmu.mak
+++ b/default-configs/alpha-softmmu.mak
@@ -4,7 +4,9 @@ include pci.mak
 CONFIG_SERIAL=y
 CONFIG_I8254=y
 CONFIG_PCKBD=y
+CONFIG_VGA=y
 CONFIG_VGA_PCI=y
+CONFIG_VGA_CIRRUS=y
 CONFIG_IDE_CORE=y
 CONFIG_IDE_QDEV=y
 CONFIG_VMWARE_VGA=y
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 8d1174f..e542b4f 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -2,6 +2,7 @@
 
 include pci.mak
 CONFIG_GDBSTUB_XML=y
+CONFIG_VGA=y
 CONFIG_ISA_MMIO=y
 CONFIG_NAND=y
 CONFIG_ECC=y
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index e67ebb3..662348e 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -1,8 +1,10 @@
 # Default configuration for i386-softmmu
 
 include pci.mak
+CONFIG_VGA=y
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
+CONFIG_VGA_CIRRUS=y
 CONFIG_VMWARE_VGA=y
 CONFIG_VMMOUSE=y
 CONFIG_SERIAL=y
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak
index 94a3486..308d04a 100644
--- a/default-configs/mips-softmmu.mak
+++ b/default-configs/mips-softmmu.mak
@@ -3,9 +3,11 @@
 include pci.mak
 CONFIG_ISA_MMIO=y
 CONFIG_ESP=y
+CONFIG_VGA=y
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
 CONFIG_VGA_ISA_MM=y
+CONFIG_VGA_CIRRUS=y
 CONFIG_VMWARE_VGA=y
 CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak
index b5d3108..f1b92da 100644
--- a/default-configs/mips64-softmmu.mak
+++ b/default-configs/mips64-softmmu.mak
@@ -3,9 +3,11 @@
 include pci.mak
 CONFIG_ISA_MMIO=y
 CONFIG_ESP=y
+CONFIG_VGA=y
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
 CONFIG_VGA_ISA_MM=y
+CONFIG_VGA_CIRRUS=y
 CONFIG_VMWARE_VGA=y
 CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index 2831f44..567396c 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -3,9 +3,11 @@
 include pci.mak
 CONFIG_ISA_MMIO=y
 CONFIG_ESP=y
+CONFIG_VGA=y
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
 CONFIG_VGA_ISA_MM=y
+CONFIG_VGA_CIRRUS=y
 CONFIG_VMWARE_VGA=y
 CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak
index 14c949d..a8e421b 100644
--- a/default-configs/mipsel-softmmu.mak
+++ b/default-configs/mipsel-softmmu.mak
@@ -3,9 +3,11 @@
 include pci.mak
 CONFIG_ISA_MMIO=y
 CONFIG_ESP=y
+CONFIG_VGA=y
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
 CONFIG_VGA_ISA_MM=y
+CONFIG_VGA_CIRRUS=y
 CONFIG_VMWARE_VGA=y
 CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index c85cdce..3277291 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -5,6 +5,7 @@ CONFIG_GDBSTUB_XML=y
 CONFIG_ISA_MMIO=y
 CONFIG_ESCC=y
 CONFIG_M48T59=y
+CONFIG_VGA=y
 CONFIG_VGA_PCI=y
 CONFIG_SERIAL=y
 CONFIG_I8254=y
diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak
index 8874115..f490368 100644
--- a/default-configs/ppc64-softmmu.mak
+++ b/default-configs/ppc64-softmmu.mak
@@ -5,6 +5,7 @@ CONFIG_GDBSTUB_XML=y
 CONFIG_ISA_MMIO=y
 CONFIG_ESCC=y
 CONFIG_M48T59=y
+CONFIG_VGA=y
 CONFIG_VGA_PCI=y
 CONFIG_SERIAL=y
 CONFIG_I8254=y
diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak
index 5db7205..829f462 100644
--- a/default-configs/ppcemb-softmmu.mak
+++ b/default-configs/ppcemb-softmmu.mak
@@ -5,6 +5,7 @@ CONFIG_GDBSTUB_XML=y
 CONFIG_ISA_MMIO=y
 CONFIG_ESCC=y
 CONFIG_M48T59=y
+CONFIG_VGA=y
 CONFIG_VGA_PCI=y
 CONFIG_SERIAL=y
 CONFIG_I8254=y
diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak
index d8f17e7..c9a36c1 100644
--- a/default-configs/sparc64-softmmu.mak
+++ b/default-configs/sparc64-softmmu.mak
@@ -4,7 +4,9 @@ include pci.mak
 CONFIG_ISA_MMIO=y
 CONFIG_M48T59=y
 CONFIG_PTIMER=y
+CONFIG_VGA=y
 CONFIG_VGA_PCI=y
+CONFIG_VGA_CIRRUS=y
 CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
 CONFIG_PCKBD=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index b75757e..b445be2 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -1,8 +1,10 @@
 # Default configuration for x86_64-softmmu
 
 include pci.mak
+CONFIG_VGA=y
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
+CONFIG_VGA_CIRRUS=y
 CONFIG_VMWARE_VGA=y
 CONFIG_VMMOUSE=y
 CONFIG_SERIAL=y
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index f7b1d3d..8506bb5 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];
 
 /***************************************
@@ -2883,23 +2888,35 @@ 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 ISADeviceInfo isa_cirrus_vga_info = {
+    .qdev.name     = "isa-cirrus-vga",
+    .qdev.size     = sizeof(ISACirrusVGAState),
+    .qdev.vmsd     = &vmstate_cirrus_vga,
+    .init          = vga_initfn,
+};
+
+static void isa_cirrus_vga_register(void)
+{
+    isa_qdev_register(&isa_cirrus_vga_info);
 }
+device_init(isa_cirrus_vga_register)
 
 /***************************************
  *
diff --git a/hw/pc.c b/hw/pc.c
index 8cb78d9..b1fd4b0 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1080,7 +1080,7 @@ 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) {
diff --git a/hw/pc.h b/hw/pc.h
index 13e41f1..58a7ea9 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -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)
commit a369da5f31ddbdeb32a7f76622e480d3995fbb00
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Tue Sep 27 19:15:42 2011 +0000

    vga: improve VGA logic
    
    Improve VGA selection logic, push check for device availabilty to vl.c.
    Create the devices at board level unconditionally.
    
    Remove now unused pci_try_create*() functions.
    
    Make PCI VGA devices optional.
    
    Reviewed-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c
index e975702..6735577 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/boards.h b/hw/boards.h
index 716fd7b..f6d3784 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/mips_malta.c b/hw/mips_malta.c
index e625ec3..4a4f76d 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);
     }
diff --git a/hw/pc.c b/hw/pc.c
index 85304cf..8cb78d9 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1085,11 +1085,6 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus)
     } 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/pci.c b/hw/pci.c
index c3082bc..54400ac 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1572,21 +1572,6 @@ PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool 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);
-}
-
 PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
                                            bool multifunction,
                                            const char *name)
@@ -1606,11 +1591,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);
diff --git a/hw/pci.h b/hw/pci.h
index 0d2cff6..5501d95 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -469,12 +469,8 @@ PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
 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/qdev.c b/hw/qdev.c
index e59f345..5a75668 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -80,6 +80,10 @@ static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
     return NULL;
 }
 
+bool qdev_exists(const char *name)
+{
+    return !!qdev_find_info(NULL, name);
+}
 static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
                                      Error **errp);
 
diff --git a/hw/qdev.h b/hw/qdev.h
index 2abb767..6b58dd8 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -179,6 +179,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;
diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
index 2210b8a..51123a7 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/spapr.c b/hw/spapr.c
index b011371..dffb6a2 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -740,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/vmware_vga.h b/hw/vmware_vga.h
index db11cbf..000fbdd 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/vl.c b/vl.c
index ba55b35..d5868b1 100644
--- a/vl.c
+++ b/vl.c
@@ -271,7 +271,6 @@ static int default_serial = 1;
 static int default_parallel = 1;
 static int default_virtcon = 1;
 static int default_monitor = 1;
-static int default_vga = 1;
 static int default_floppy = 1;
 static int default_cdrom = 1;
 static int default_sdcard = 1;
@@ -290,11 +289,6 @@ static struct {
     { .driver = "virtio-serial-pci",    .flag = &default_virtcon   },
     { .driver = "virtio-serial-s390",   .flag = &default_virtcon   },
     { .driver = "virtio-serial",        .flag = &default_virtcon   },
-    { .driver = "VGA",                  .flag = &default_vga       },
-    { .driver = "cirrus-vga",           .flag = &default_vga       },
-    { .driver = "vmware-svga",          .flag = &default_vga       },
-    { .driver = "isa-vga",              .flag = &default_vga       },
-    { .driver = "qxl-vga",              .flag = &default_vga       },
 };
 
 static void res_free(void)
@@ -1525,18 +1519,48 @@ static const QEMUOption qemu_options[] = {
 #include "qemu-options-wrapper.h"
     { NULL },
 };
+
+static bool vga_available(void)
+{
+    return qdev_exists("VGA") || qdev_exists("isa-vga");
+}
+
+static bool cirrus_vga_available(void)
+{
+    return qdev_exists("cirrus-vga") || qdev_exists("isa-cirrus-vga");
+}
+
+static bool vmware_vga_available(void)
+{
+    return qdev_exists("vmware-svga");
+}
+
 static void select_vgahw (const char *p)
 {
     const char *opts;
 
-    default_vga = 0;
     vga_interface_type = VGA_NONE;
     if (strstart(p, "std", &opts)) {
-        vga_interface_type = VGA_STD;
+        if (vga_available()) {
+            vga_interface_type = VGA_STD;
+        } else {
+            fprintf(stderr, "Error: standard VGA not available\n");
+            exit(0);
+        }
     } else if (strstart(p, "cirrus", &opts)) {
-        vga_interface_type = VGA_CIRRUS;
+        if (cirrus_vga_available()) {
+            vga_interface_type = VGA_CIRRUS;
+        } else {
+            fprintf(stderr, "Error: Cirrus VGA not available\n");
+            exit(0);
+        }
     } else if (strstart(p, "vmware", &opts)) {
-        vga_interface_type = VGA_VMWARE;
+        if (vmware_vga_available()) {
+            vga_interface_type = VGA_VMWARE;
+        } else {
+            fprintf(stderr, "Error: VMWare SVGA not available\n");
+            exit(0);
+        }
     } else if (strstart(p, "xenfb", &opts)) {
         vga_interface_type = VGA_XENFB;
     } else if (strstart(p, "qxl", &opts)) {
@@ -2155,6 +2179,7 @@ int main(int argc, char **argv, char **envp)
     const char *loadvm = NULL;
     QEMUMachine *machine;
     const char *cpu_model;
+    const char *vga_model = NULL;
     const char *pid_file = NULL;
     const char *incoming = NULL;
 #ifdef CONFIG_VNC
@@ -2581,7 +2606,7 @@ int main(int argc, char **argv, char **envp)
                 rtc_utc = 0;
                 break;
             case QEMU_OPTION_vga:
-                select_vgahw (optarg);
+                vga_model = optarg;
                 break;
             case QEMU_OPTION_g:
                 {
@@ -2978,7 +3003,6 @@ int main(int argc, char **argv, char **envp)
                 default_parallel = 0;
                 default_virtcon = 0;
                 default_monitor = 0;
-                default_vga = 0;
                 default_net = 0;
                 default_floppy = 0;
                 default_cdrom = 0;
@@ -3140,9 +3164,6 @@ int main(int argc, char **argv, char **envp)
     if (!machine->use_virtcon) {
         default_virtcon = 0;
     }
-    if (machine->no_vga) {
-        default_vga = 0;
-    }
     if (machine->no_floppy) {
         default_floppy = 0;
     }
@@ -3178,8 +3199,6 @@ int main(int argc, char **argv, char **envp)
         if (default_virtcon)
             add_device_config(DEV_VIRTCON, "vc:80Cx24C");
     }
-    if (default_vga)
-        vga_interface_type = VGA_CIRRUS;
 
     socket_init();
 
@@ -3330,6 +3349,15 @@ int main(int argc, char **argv, char **envp)
 
     module_call_init(MODULE_INIT_DEVICE);
 
+    /* must be after qdev registration but before machine init */
+    if (vga_model) {
+        select_vgahw(vga_model);
+    } else if (cirrus_vga_available()) {
+        select_vgahw("cirrus");
+    } else {
+        select_vgahw("none");
+    }
+
     if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0) != 0)
         exit(0);
 
commit 0ae469969484e93354f307971b3425bafe51cb35
Author: Andreas Färber <afaerber at suse.de>
Date:   Wed Jan 18 00:11:16 2012 +0000

    grackle_pci: Clean up qdev names
    
    Rename SysBus device from 'grackle' to 'grackle-pcihost' to resolve a
    name conflict.
    
    Also mark both devices as no_user.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Cc: Alexander Graf <agraf at suse.de>
    Cc: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index 1e529fb..be10a6d 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,9 +121,10 @@ static int grackle_pci_host_init(PCIDevice *d)
     return 0;
 }
 
-static PCIDeviceInfo grackle_pci_host_info = {
+static PCIDeviceInfo grackle_pci_info = {
     .qdev.name = "grackle",
     .qdev.size = sizeof(PCIDevice),
+    .qdev.no_user = 1,
     .init      = grackle_pci_host_init,
     .vendor_id = PCI_VENDOR_ID_MOTOROLA,
     .device_id = PCI_DEVICE_ID_MOTOROLA_MPC106,
@@ -131,11 +132,17 @@ static PCIDeviceInfo grackle_pci_host_info = {
     .class_id  = PCI_CLASS_BRIDGE_HOST,
 };
 
+static SysBusDeviceInfo grackle_pci_host_info = {
+    .qdev.name = "grackle-pcihost",
+    .qdev.size = sizeof(GrackleState),
+    .qdev.no_user = 1,
+    .init = pci_grackle_init_device,
+};
+
 static void grackle_register_devices(void)
 {
-    sysbus_register_dev("grackle", sizeof(GrackleState),
-                        pci_grackle_init_device);
-    pci_qdev_register(&grackle_pci_host_info);
+    sysbus_register_withprop(&grackle_pci_host_info);
+    pci_qdev_register(&grackle_pci_info);
 }
 
 device_init(grackle_register_devices)
commit d5ee67549a9b51c5a62831f506e33286923fbbd9
Author: Andreas Färber <afaerber at suse.de>
Date:   Wed Jan 18 06:20:43 2012 +0000

    MAINTAINERS: Add PCI-PCI bridge to New World Mac machine
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/MAINTAINERS b/MAINTAINERS
index f7fc2ba..87237a6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -301,6 +301,7 @@ L: qemu-ppc at nongnu.org
 S: Maintained
 F: hw/ppc_newworld.c
 F: hw/unin_pci.c
+F: hw/dec_pci.[hc]
 
 Old World
 M: Alexander Graf <agraf at suse.de>
commit 88045ac55592cacc92567aa46cb6917854bf7241
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Jan 18 16:42:09 2012 +0100

    PPC: Pseries: Check for PCI boundaries
    
    We call pci_host_config_{read,write}_common() which perform PCI config
    accesses. However they don't do all limit checking the way we expect
    it to.
    
    So let's introduce a small wrapper around them, making them behave the
    way we would without touching generic code.
    
    This patch is based on a patch by David Gibson which put this logic into
    the generic code.
    
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index cf37628..2c95faa 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -67,6 +67,25 @@ 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,
@@ -82,7 +101,7 @@ static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
     }
     size = rtas_ld(args, 3);
     addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
-    val = pci_host_config_read_common(dev, addr, pci_config_size(dev), size);
+    val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size);
     rtas_st(rets, 0, 0);
     rtas_st(rets, 1, val);
 }
@@ -101,7 +120,7 @@ static void rtas_read_pci_config(sPAPREnvironment *spapr,
     }
     size = rtas_ld(args, 1);
     addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
-    val = pci_host_config_read_common(dev, addr, pci_config_size(dev), size);
+    val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size);
     rtas_st(rets, 0, 0);
     rtas_st(rets, 1, val);
 }
@@ -122,7 +141,7 @@ static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr,
     val = rtas_ld(args, 4);
     size = rtas_ld(args, 3);
     addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
-    pci_host_config_write_common(dev, addr, pci_config_size(dev), val, size);
+    rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size);
     rtas_st(rets, 0, 0);
 }
 
@@ -141,7 +160,7 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr,
     val = rtas_ld(args, 2);
     size = rtas_ld(args, 1);
     addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
-    pci_host_config_write_common(dev, addr, pci_config_size(dev), val, size);
+    rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size);
     rtas_st(rets, 0, 0);
 }
 
commit 0a6eec6bbf0afc253bd4253902bd65226914cb6b
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Fri Jan 13 13:33:58 2012 +0000

    MAINTAINERS: Add PCI host bridge files to CHRP machines
    
    Just like prep_pci.c, these were not associated with any MAINTAINERS
    section, including PCI.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Cc: Alexander Graf <agraf at suse.de>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/MAINTAINERS b/MAINTAINERS
index a3bdb41..f7fc2ba 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -300,12 +300,14 @@ M: Alexander Graf <agraf at suse.de>
 L: qemu-ppc at nongnu.org
 S: Maintained
 F: hw/ppc_newworld.c
+F: hw/unin_pci.c
 
 Old World
 M: Alexander Graf <agraf at suse.de>
 L: qemu-ppc at nongnu.org
 S: Maintained
 F: hw/ppc_oldworld.c
+F: hw/grackle_pci.c
 
 PReP
 M: Andreas Färber <andreas.faerber at web.de>
commit a6c986851434e265525a2168766fd3f7a95ca760
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Fri Jan 13 13:33:57 2012 +0000

    MAINTAINERS: Add qemu-ppc to all ppc target stuff
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Cc: Alexander Graf <agraf at suse.de>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/MAINTAINERS b/MAINTAINERS
index de2a916..a3bdb41 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -93,6 +93,7 @@ F: target-mips/
 
 PowerPC
 M: Alexander Graf <agraf at suse.de>
+L: qemu-ppc at nongnu.org
 S: Maintained
 F: target-ppc/
 
@@ -290,21 +291,25 @@ PowerPC Machines
 ----------------
 405
 M: Alexander Graf <agraf at suse.de>
+L: qemu-ppc at nongnu.org
 S: Maintained
 F: hw/ppc405_boards.c
 
 New World
 M: Alexander Graf <agraf at suse.de>
+L: qemu-ppc at nongnu.org
 S: Maintained
 F: hw/ppc_newworld.c
 
 Old World
 M: Alexander Graf <agraf at suse.de>
+L: qemu-ppc at nongnu.org
 S: Maintained
 F: hw/ppc_oldworld.c
 
 PReP
 M: Andreas Färber <andreas.faerber at web.de>
+L: qemu-ppc at nongnu.org
 S: Odd Fixes
 F: hw/ppc_prep.c
 
commit 4d8d5467cd6e324fb49ae97b9d5dcee3973d9a19
Author: Benjamin Herrenschmidt <benh at kernel.crashing.org>
Date:   Wed Jan 11 19:46:28 2012 +0000

    pseries: SLOF PCI flag day
    
    Currently on the pseries machine the SLOF firmware is used normally,
    but we bypass it when -kernel is specified.  Having these two
    
    different boot paths can cause some confusion.
    
    In particular at present we need to "probe" the (emulated) PCI bus and
    produce device tree nodes for the PCI devices in qemu, for the -kernel
    case.  In the SLOF case, it takes the device tree from qemu adds some
    stuff to it then passes it on to the kernel.
    
    It's been decided that a better approach is to always boot through
    SLOF, even when using -kernel.  WIth this approach we can leave PCI
    probing and device node creation to SLOF in all cases which removes a
    bunch of code in qemu, and avoids iterating the PCI devices from the
    machine specific init code which we're not supposed to do.
    
    This patch changes qemu to always boot through SLOF, and not to create
    PCI nodes.  Simultaneously it updates the included version of SLOF
    (submodule and binary image) to one which supports (and requires) the
    new approach.
    
    The new SLOF version also includes a number of unrelated enhancements:
    support for booting from virtio-pci devices and e1000, greatly
    improved FCode support and many bugfixes.  It also makes SLOF ready to
    be used even when specifying a kernel on the qemu command line.
    
    Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr.c b/hw/spapr.c
index 0e1f80d..b011371 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);
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index f3f9246..cf37628 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -324,31 +324,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;
@@ -369,7 +351,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 */
@@ -397,118 +379,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(fdt, bus_off, "interrupt-map-mask",
-                     &interrupt_map_mask, sizeof(interrupt_map_mask)));
     _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1));
 
-    /* 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));
+    /* 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)));
+    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/pc-bios/README b/pc-bios/README
index 1cebbbc..5dce355 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -17,7 +17,7 @@
 - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
   implementation for certain IBM POWER hardware.  The sources are at
   https://github.com/dgibson/SLOF, and the image currently in qemu is
-  built from git tag qemu-slof-20111013.
+  built from git tag qemu-slof-20120111.1.
 
 - sgabios (the Serial Graphics Adapter option ROM) provides a means for
   legacy x86 software to communicate with an attached serial console as
diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin
index 1e84582..8554f54 100644
Binary files a/pc-bios/slof.bin and b/pc-bios/slof.bin differ
diff --git a/roms/SLOF b/roms/SLOF
index 32e3430..ab062ff 160000
--- a/roms/SLOF
+++ b/roms/SLOF
@@ -1 +1 @@
-Subproject commit 32e3430c018ceb8413cb808477449d1968c42497
+Subproject commit ab062ff3b37c39649f2b0d94ed607adc6f6b3c7d
commit c9c3c80af71dd2b7813d1ada9b14cb51df584221
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Wed Jan 11 19:46:26 2012 +0000

    pseries: Use correct dispatcher for PCI config space accesses
    
    The pseries machine expects a para-virtualized guest and so supplies RTAS
    functions (via a hypercall) for performing PCI config space access.
    Currently the implementation of these calls into
    pci_default_{read,write}_config().  However this would be incorrect for
    any PCI device which overrides the default config read/write functions.
    AFAICT there's only one such device today, but we should still get it
    right.  In addition the pci_host_config_{read,write}_common() functions
    which do correctly do this dispatch, perform bounds checking on the config
    space address, lack of which currently leads to an exploitable bug.
    
    This patch corrects the problem.
    
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index 2550e19..f3f9246 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -82,7 +82,7 @@ static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
     }
     size = rtas_ld(args, 3);
     addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
-    val = pci_default_read_config(dev, addr, size);
+    val = pci_host_config_read_common(dev, addr, pci_config_size(dev), size);
     rtas_st(rets, 0, 0);
     rtas_st(rets, 1, val);
 }
@@ -101,7 +101,7 @@ static void rtas_read_pci_config(sPAPREnvironment *spapr,
     }
     size = rtas_ld(args, 1);
     addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
-    val = pci_default_read_config(dev, addr, size);
+    val = pci_host_config_read_common(dev, addr, pci_config_size(dev), size);
     rtas_st(rets, 0, 0);
     rtas_st(rets, 1, val);
 }
@@ -122,7 +122,7 @@ static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr,
     val = rtas_ld(args, 4);
     size = rtas_ld(args, 3);
     addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
-    pci_default_write_config(dev, addr, val, size);
+    pci_host_config_write_common(dev, addr, pci_config_size(dev), val, size);
     rtas_st(rets, 0, 0);
 }
 
@@ -141,7 +141,7 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr,
     val = rtas_ld(args, 2);
     size = rtas_ld(args, 1);
     addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
-    pci_default_write_config(dev, addr, val, size);
+    pci_host_config_write_common(dev, addr, pci_config_size(dev), val, size);
     rtas_st(rets, 0, 0);
 }
 
commit 3f7565c957c14e4600d471791fca8e534c1ad0b7
Author: Benjamin Herrenschmidt <benh at kernel.crashing.org>
Date:   Wed Jan 11 19:46:25 2012 +0000

    pseries: Support PCI extended config space in RTAS calls
    
    On the pseries machine (which expexts a paravirtualized guest), guest
    access to PCI config space is via host-provided RTAS functions.  This
    patch extends these RTAS functions to permit access to PCI extended
    config space, as specified in PAPR.
    
    Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index 9b6a032..2550e19 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -62,6 +62,11 @@ static PCIDevice *find_dev(sPAPREnvironment *spapr,
     return NULL;
 }
 
+static uint32_t rtas_pci_cfgaddr(uint32_t arg)
+{
+    return ((arg >> 20) & 0xf00) | (arg & 0xff);
+}
+
 static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
                                      uint32_t token, uint32_t nargs,
                                      target_ulong args,
@@ -76,7 +81,7 @@ static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
         return;
     }
     size = rtas_ld(args, 3);
-    addr = rtas_ld(args, 0) & 0xFF;
+    addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
     val = pci_default_read_config(dev, addr, size);
     rtas_st(rets, 0, 0);
     rtas_st(rets, 1, val);
@@ -95,7 +100,7 @@ static void rtas_read_pci_config(sPAPREnvironment *spapr,
         return;
     }
     size = rtas_ld(args, 1);
-    addr = rtas_ld(args, 0) & 0xFF;
+    addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
     val = pci_default_read_config(dev, addr, size);
     rtas_st(rets, 0, 0);
     rtas_st(rets, 1, val);
@@ -116,7 +121,7 @@ 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;
+    addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
     pci_default_write_config(dev, addr, val, size);
     rtas_st(rets, 0, 0);
 }
@@ -135,7 +140,7 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr,
     }
     val = rtas_ld(args, 2);
     size = rtas_ld(args, 1);
-    addr = rtas_ld(args, 0) & 0xFF;
+    addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
     pci_default_write_config(dev, addr, val, size);
     rtas_st(rets, 0, 0);
 }
@@ -394,6 +399,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
     _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
     _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask",
                      &interrupt_map_mask, sizeof(interrupt_map_mask)));
+    _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1));
 
     /* Populate PCI devices and allocate IRQs */
     devices = 0;
commit 964455f39ed540e5968ec3000a3fb3d8fb20823c
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Wed Jan 11 19:46:24 2012 +0000

    Correct types in bmdma_addr_{read,write}
    
    Back when I made patches introducing dma_addr_t and various PCI DMA
    wrapper functions, I made a mistake.  The bmdma_addr_{read,write} functions
    need to take target_phys_addr_t not dma_addr_t, since they are assigned
    to MemoryRegionOps callbacks.
    
    This patch corrects my error.
    
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index cb3de65..246dd57 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;
commit 033276a7d1701c98bb478341c13d2e1c6692b688
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Wed Jan 11 19:46:23 2012 +0000

    Update gitignore file
    
    This patch adds several auto-generated files to .gitignore which were
    previously missing.
    
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/.gitignore b/.gitignore
index 406f75f..f5aab2c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,10 @@ qemu-ga
 qemu-monitor.texi
 QMP/qmp-commands.txt
 test-coroutine
+test-qmp-input-visitor
+test-qmp-output-visitor
+fsdev/virtfs-proxy-helper.1
+fsdev/virtfs-proxy-helper.pod
 .gdbinit
 *.a
 *.aux
commit aa90fec7ad128039617d31a5fd5ced8b0488f71b
Author: Benjamin Herrenschmidt <benh at kernel.crashing.org>
Date:   Wed Jan 11 19:46:21 2012 +0000

    Fix dirty logging with 32-bit qemu & 64-bit guests
    
    The kvm_get_dirty_pages_log_range() function uses two address
    variables to step through the monitored memory region to update the
    dirty log.  However, these variables have type unsigned long, which
    can overflow if running a 64-bit guest with a 32-bit qemu binary.
    
    This patch changes these to target_phys_addr_t which will have the
    correct size.
    
    Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/kvm-all.c b/kvm-all.c
index 2cc4562..9e84d35 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -344,7 +344,8 @@ static int kvm_get_dirty_pages_log_range(MemoryRegionSection *section,
                                          unsigned long *bitmap)
 {
     unsigned int i, j;
-    unsigned long page_number, addr, addr1, c;
+    unsigned long page_number, c;
+    target_phys_addr_t addr, addr1;
     unsigned int len = ((section->size / TARGET_PAGE_SIZE) + HOST_LONG_BITS - 1) / HOST_LONG_BITS;
 
     /*
commit 17df768c1e4580f03301d18ea938d3557d441911
Author: Benjamin Herrenschmidt <benh at kernel.crashing.org>
Date:   Wed Jan 11 19:46:20 2012 +0000

    load_image_targphys() should enforce the max size
    
    load_image_targphys() gets passed a max size for the file, but doesn't
    enforce it at all. Add a check and return -1 (error) if the file is
    too big, without loading it.  Fix the bracing style in the function
    while we're at it.
    
    Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/loader.c b/hw/loader.c
index 446b628..415cdce 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;
 }
 
commit 06dbfc6f8833475065c9cf5fdbdb990dbb4b619b
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 10 23:33:10 2012 +0100

    virtio: change memcpy to guest reads
    
    When accessing the device specific virtio config space, we memcpy
    the data into a variable in QEMU. At that point we're basically
    pulling host endianness into the game which is a really bad idea.
    
    So instead, let's use the target specific load/store helpers for
    memory pointers which fetch things in target endianness. The whole
    array is already populated in target endianness anyways
    (see virtio-blk).
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/virtio.c b/hw/virtio.c
index 81ecc40..74cc038 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);
commit 82afa58641b0e67abbaf4da6c325ebd7c2513262
Author: Benjamin Herrenschmidt <benh at kernel.crashing.org>
Date:   Tue Jan 10 01:35:11 2012 +0000

    virtio-pci: Fix endianness of virtio config
    
    The virtio config area in PIO space is a bit special. The initial
    header is little endian but the rest (device specific) is guest
    native endian.
    
    The PIO accessors for PCI on machines that don't have native IO ports
    assume that all PIO is little endian, which works fine for everything
    except the above.
    
    A complicated way to fix it would be to split the BAR into two memory
    regions with different endianess settings, but this isn't practical
    to do, besides, the PIO code doesn't honor region endianness anyway
    (I have a patch for that too but it isn't necessary at this stage).
    
    So I decided to go for the quick fix instead which consists of
    reverting the swap in virtio-pci in selected places, hoping that when
    we eventually do a "v2" of the virtio protocols, we sort that out once
    and for all using a fixed endian setting for everything.
    
    Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
    Signed-off-by: Alexander Graf <agraf at suse.de>
    [agraf: keep virtio in libhw and determine endianness through a
            helper function in exec.c]
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/exec.c b/exec.c
index 7f9f730..5b9eb9a 100644
--- a/exec.c
+++ b/exec.c
@@ -4390,6 +4390,20 @@ tb_page_addr_t get_page_addr_code(CPUState *env1, target_ulong addr)
     return qemu_ram_addr_from_host_nofail(p);
 }
 
+/*
+ * A helper function for the _utterly broken_ virtio device model to find out if
+ * it's running on a big endian machine. Don't do this at home kids!
+ */
+bool virtio_is_big_endian(void);
+bool virtio_is_big_endian(void)
+{
+#if defined(TARGET_WORDS_BIGENDIAN)
+    return true;
+#else
+    return false;
+#endif
+}
+
 #define MMUSUFFIX _cmmu
 #undef GETPC
 #define GETPC() NULL
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index caff0aa..c93889a 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);
 }
 
commit 34ba1dc8739196c771281b0ba38c2ccd32c6d1fe
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 10 20:11:25 2012 +0100

    PPC: Bamboo: Integrate SoC instatiation, use qdev for PCI
    
    Now that we have the SoC init function in the same file, let's integrate
    it with the board initialization.
    
    While at it, also make use of the newly qdev'ified PCI host controller.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index d00bdda..f86b168 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -27,6 +27,7 @@
 #include "ppc.h"
 #include "ppc405.h"
 #include "sysemu.h"
+#include "sysbus.h"
 
 #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
 
@@ -50,87 +51,6 @@ static const unsigned int ppc440ep_sdram_bank_sizes[] = {
 
 static target_phys_addr_t entry;
 
-static 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)
-{
-    return NULL;
-}
-
-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 = "440EP";
-    }
-    env = cpu_init(cpu_model);
-    if (!env) {
-        fprintf(stderr, "Unable to initialize CPU!\n");
-        exit(1);
-    }
-
-    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, 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;
-}
-
 static int bamboo_load_device_tree(target_phys_addr_t addr,
                                      uint32_t ramsize,
                                      target_phys_addr_t initrd_base,
@@ -245,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 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. */
commit 3960b04d6214e254e571a73d7b0de3c64230f774
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 10 19:39:38 2012 +0100

    PPC: Bamboo: fold ppc440.c and ppc440_bamboo.c into a single file
    
    The separation of ppc440 and ppc440_bamboo makes some sense, since ppc440
    is the SoC while ppc440_bamboo is the actual board. But the separation
    makes things harder for us for no good reason, so let's just fold them
    in together with each other.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/Makefile.target b/Makefile.target
index 06d79b8..a67e1fe 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -250,7 +250,7 @@ obj-ppc-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
 obj-ppc-$(CONFIG_PSERIES) += spapr_pci.o device-hotplug.o pci-hotplug.o
 # PowerPC 4xx boards
 obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
-obj-ppc-y += ppc440.o ppc440_bamboo.o
+obj-ppc-y += ppc440_bamboo.o
 # PowerPC E500 boards
 obj-ppc-y += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o
 # PowerPC 440 Xilinx ML507 reference board.
diff --git a/hw/ppc440.c b/hw/ppc440.c
deleted file mode 100644
index 8920abb..0000000
--- a/hw/ppc440.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Qemu PowerPC 440 chip emulation
- *
- * Copyright 2007 IBM Corporation.
- * Authors:
- * 	Jerone Young <jyoung5 at us.ibm.com>
- * 	Christian Ehrhardt <ehrhardt at linux.vnet.ibm.com>
- * 	Hollis Blanchard <hollisb at 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 = "440EP";
-    }
-    env = cpu_init(cpu_model);
-    if (!env) {
-        fprintf(stderr, "Unable to initialize CPU!\n");
-        exit(1);
-    }
-
-    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, 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 9c27c36..0000000
--- a/hw/ppc440.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Qemu PowerPC 440 board emualtion
- *
- * Copyright 2007 IBM Corporation.
- * Authors: Jerone Young <jyoung5 at us.ibm.com>
- * 	    Christian Ehrhardt <ehrhardt at 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 124e7d7..d00bdda 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -17,13 +17,16 @@
 #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"
 
 #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
 
@@ -32,6 +35,19 @@
 #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 PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
@@ -43,6 +59,78 @@ static PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
     return NULL;
 }
 
+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 = "440EP";
+    }
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to initialize CPU!\n");
+        exit(1);
+    }
+
+    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, 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;
+}
+
 static int bamboo_load_device_tree(target_phys_addr_t addr,
                                      uint32_t ramsize,
                                      target_phys_addr_t initrd_base,
diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c
index bd16b97..f8d2b1b 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"
commit 623f7c2172d6080b2ee3132d6e80e8667609c16a
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 10 19:36:26 2012 +0100

    PPC: 4xx: Qdevify the 440 PCI host controller
    
    Due to popular demand, this qdevifies the PCI host controller of 4xx SoCs
    the same way as e500.
    
    We have to introduce a small stub function for pci init that will be
    removed in a later patch, once we qdev'ified the board, to keep the build
    working.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index 2369fba..124e7d7 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -34,6 +34,15 @@
 
 static target_phys_addr_t entry;
 
+static 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)
+{
+    return NULL;
+}
+
 static int bamboo_load_device_tree(target_phys_addr_t addr,
                                      uint32_t ramsize,
                                      target_phys_addr_t initrd_base,
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index 1bf785b..26de007 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)
@@ -314,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),
@@ -326,60 +328,63 @@ 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 PCIDeviceInfo ppc4xx_host_bridge_info = {
+    .qdev.name    = "ppc4xx-host-bridge",
+    .qdev.desc    = "Host bridge",
+    .qdev.size    = sizeof(PCIDevice),
+    .vendor_id    = PCI_VENDOR_ID_IBM,
+    .device_id    = PCI_DEVICE_ID_IBM_440GX,
+    .class_id     = PCI_CLASS_BRIDGE_OTHER,
+};
+
+static SysBusDeviceInfo ppc4xx_pcihost_info = {
+    .init         = ppc4xx_pcihost_initfn,
+    .qdev.name    = "ppc4xx-pcihost",
+    .qdev.size    = sizeof(PPC4xxPCIState),
+    .qdev.vmsd    = &vmstate_ppc4xx_pci,
+};
+
+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;
+    sysbus_register_withprop(&ppc4xx_pcihost_info);
+    pci_qdev_register(&ppc4xx_host_bridge_info);
 }
+device_init(ppc4xx_pci_register);
commit acd1bf9083dc83e0ef756dbdc81a9805bfb43167
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 10 16:49:22 2012 +0100

    PPC: bamboo: fix whitespace
    
    Tabs followed by spaces are a no-go. My editor shows it red, distracting
    me from actual work! :)
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index 84e45b4..2369fba 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -3,9 +3,9 @@
  *
  * Copyright 2007 IBM Corporation.
  * Authors:
- * 	Jerone Young <jyoung5 at us.ibm.com>
- * 	Christian Ehrhardt <ehrhardt at linux.vnet.ibm.com>
- * 	Hollis Blanchard <hollisb at us.ibm.com>
+ *	Jerone Young <jyoung5 at us.ibm.com>
+ *	Christian Ehrhardt <ehrhardt at linux.vnet.ibm.com>
+ *	Hollis Blanchard <hollisb at us.ibm.com>
  *
  * This work is licensed under the GNU GPL license version 2 or later.
  *
commit d3c4548b8e2954a33d2d713e4e67d8deda7d97bf
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 10 16:36:10 2012 +0100

    PPC: bamboo: remove old machine descriptions
    
    Nobody needs to run bamboo in 0.12 compat mode. Remove the machine.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index c17f6f7..84e45b4 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -214,34 +214,14 @@ static void bamboo_init(ram_addr_t ram_size,
 }
 
 static QEMUMachine bamboo_machine = {
-    .name = "bamboo-0.13",
-    .alias = "bamboo",
+    .name = "bamboo",
     .desc = "bamboo",
     .init = bamboo_init,
 };
 
-static QEMUMachine bamboo_machine_v0_12 = {
-    .name = "bamboo-0.12",
-    .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);
commit c0a7e81ac4182a117e176921cbee5697615c5bf8
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 3 22:01:40 2012 +0100

    PPC: Enable 440EP CPU target
    
    Now that we have 440 TLB emulation, we can also support running the 440EP
    CPU target in system emulation mode.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 47d73a6..4d692d0 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -3516,6 +3516,9 @@ static void init_proc_405 (CPUPPCState *env)
 
 /* PowerPC 440 EP                                                            */
 #define POWERPC_INSNS_440EP  (PPC_INSNS_BASE | PPC_STRING |                   \
+                              PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
                               PPC_DCR | PPC_WRTEE | PPC_RFMCI |               \
                               PPC_CACHE | PPC_CACHE_ICBI |                    \
                               PPC_CACHE_DCBZ | PPC_CACHE_DCBA |               \
@@ -3523,7 +3526,7 @@ static void init_proc_405 (CPUPPCState *env)
                               PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
                               PPC_440_SPEC)
 #define POWERPC_INSNS2_440EP (PPC_NONE)
-#define POWERPC_MSRM_440EP   (0x000000000006D630ULL)
+#define POWERPC_MSRM_440EP   (0x000000000006FF30ULL)
 #define POWERPC_MMU_440EP    (POWERPC_MMU_BOOKE)
 #define POWERPC_EXCP_440EP   (POWERPC_EXCP_BOOKE)
 #define POWERPC_INPUT_440EP  (PPC_FLAGS_INPUT_BookE)
@@ -3532,7 +3535,6 @@ static void init_proc_405 (CPUPPCState *env)
                               POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK)
 #define check_pow_440EP      check_pow_nocheck
 
-__attribute__ (( unused ))
 static void init_proc_440EP (CPUPPCState *env)
 {
     /* Time base */
@@ -3593,7 +3595,7 @@ static void init_proc_440EP (CPUPPCState *env)
     init_excp_BookE(env);
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
-    /* XXX: TODO: allocate internal IRQ controller */
+    ppc40x_irq_init(env);
 
     SET_FIT_PERIOD(12, 16, 20, 24);
     SET_WDT_PERIOD(20, 24, 28, 32);
@@ -7869,22 +7871,14 @@ static const ppc_def_t ppc_defs[] = {
     POWERPC_DEF("440H6",         CPU_POWERPC_440H6,                  440Gx5),
 #endif
     /* PowerPC 440 microcontrolers                                           */
-#if defined(TODO_USER_ONLY)
     /* PowerPC 440 EP                                                        */
     POWERPC_DEF("440EP",         CPU_POWERPC_440EP,                  440EP),
-#endif
-#if defined(TODO_USER_ONLY)
     /* PowerPC 440 EPa                                                       */
     POWERPC_DEF("440EPa",        CPU_POWERPC_440EPa,                 440EP),
-#endif
-#if defined(TODO_USER_ONLY)
     /* PowerPC 440 EPb                                                       */
     POWERPC_DEF("440EPb",        CPU_POWERPC_440EPb,                 440EP),
-#endif
-#if defined(TODO_USER_ONLY)
     /* PowerPC 440 EPX                                                       */
     POWERPC_DEF("440EPX",        CPU_POWERPC_440EPX,                 440EP),
-#endif
 #if defined(TODO_USER_ONLY)
     /* PowerPC 440 GP                                                        */
     POWERPC_DEF("440GP",         CPU_POWERPC_440GP,                  440GP),
commit e5ba83c53add51796e8ea787d2b7cb1f9c3cb72d
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 3 22:00:23 2012 +0100

    PPC: 440: Default to 440EP CPU
    
    Today we're exposing a Virtex 440 CPU to the guest despite the fact
    that we're telling the guest that we're running on a 440EP one in the
    device tree.
    
    So let's better default to a real 440EP to make things synced again.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc440.c b/hw/ppc440.c
index f7779bf..8920abb 100644
--- a/hw/ppc440.c
+++ b/hw/ppc440.c
@@ -48,7 +48,7 @@ CPUState *ppc440ep_init(MemoryRegion *address_space_mem, ram_addr_t *ram_size,
     qemu_irq *pci_irqs;
 
     if (cpu_model == NULL) {
-        cpu_model = "440-Xilinx"; // XXX: should be 440EP
+        cpu_model = "440EP";
     }
     env = cpu_init(cpu_model);
     if (!env) {
commit c148b2b47a602024f22234f7b4ec6beedca871d2
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 3 21:58:57 2012 +0100

    PPC: Bamboo: recompile device tree
    
    Recent dtc doesn't compile our dts anymore. Change all hex numbers to have
    0x prefixes, indicate the old version and recompile using recent dtc.
    
    This doesn't change any semantics in the device tree.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/pc-bios/bamboo.dtb b/pc-bios/bamboo.dtb
index c78e254..d12e201 100644
Binary files a/pc-bios/bamboo.dtb and b/pc-bios/bamboo.dtb differ
diff --git a/pc-bios/bamboo.dts b/pc-bios/bamboo.dts
index 655442c..62fabcc 100644
--- a/pc-bios/bamboo.dts
+++ b/pc-bios/bamboo.dts
@@ -9,12 +9,14 @@
  * any warranty of any kind, whether express or implied.
  */
 
+/dts-v1/;
+
 / {
 	#address-cells = <2>;
 	#size-cells = <1>;
 	model = "amcc,bamboo";
 	compatible = "amcc,bamboo";
-	dcr-parent = <&/cpus/cpu at 0>;
+	dcr-parent = <&{/cpus/cpu at 0}>;
 
 	aliases {
 		serial0 = &UART0;
@@ -29,12 +31,12 @@
 			device_type = "cpu";
 			model = "PowerPC,440EP";
 			reg = <0>;
-			clock-frequency = <1fca0550>;
-			timebase-frequency = <017d7840>;
-			i-cache-line-size = <20>;
-			d-cache-line-size = <20>;
-			i-cache-size = <8000>;
-			d-cache-size = <8000>;
+			clock-frequency = <0x1fca0550>;
+			timebase-frequency = <0x017d7840>;
+			i-cache-line-size = <0x20>;
+			d-cache-line-size = <0x20>;
+			i-cache-size = <0x8000>;
+			d-cache-size = <0x8000>;
 			dcr-controller;
 			dcr-access-method = "native";
 		};
@@ -42,40 +44,27 @@
 
 	memory {
 		device_type = "memory";
-		reg = <0 0 9000000>;
+		reg = <0x0 0x0 0x9000000>;
 	};
 
 	UIC0: interrupt-controller0 {
 		compatible = "ibm,uic-440ep","ibm,uic";
 		interrupt-controller;
-		cell-index = <0>;
-		dcr-reg = <0c0 009>;
-		#address-cells = <0>;
-		#size-cells = <0>;
-		#interrupt-cells = <2>;
-	};
-/*
-	UIC1: interrupt-controller1 {
-		compatible = "ibm,uic-440ep","ibm,uic";
-		interrupt-controller;
-		cell-index = <1>;
-		dcr-reg = <0d0 009>;
-		#address-cells = <0>;
-		#size-cells = <0>;
-		#interrupt-cells = <2>;
-		interrupts = <1e 4 1f 4>;
-		interrupt-parent = <&UIC0>;
+		cell-index = <0x0>;
+		dcr-reg = <0x0c0 0x009>;
+		#address-cells = <0x0>;
+		#size-cells = <0x0>;
+		#interrupt-cells = <0x2>;
 	};
-*/
 
 	SDR0: sdr {
 		compatible = "ibm,sdr-440ep";
-		dcr-reg = <00e 002>;
+		dcr-reg = <0x00e 0x002>;
 	};
 
 	CPR0: cpr {
 		compatible = "ibm,cpr-440ep";
-		dcr-reg = <00c 002>;
+		dcr-reg = <0x00c 0x002>;
 	};
 
 	plb {
@@ -83,16 +72,16 @@
 		#address-cells = <2>;
 		#size-cells = <1>;
 		ranges;
-		clock-frequency = <07f28154>;
+		clock-frequency = <0x07f28154>;
 
 		SDRAM0: sdram {
 			compatible = "ibm,sdram-440ep", "ibm,sdram-405gp";
-			dcr-reg = <010 2>;
+			dcr-reg = <0x010 0x2>;
 		};
 
 		DMA0: dma {
 			compatible = "ibm,dma-440ep", "ibm,dma-440gp";
-			dcr-reg = <100 027>;
+			dcr-reg = <0x100 0x027>;
 		};
 
 		POB0: opb {
@@ -102,18 +91,18 @@
 			/* Bamboo is oddball in the 44x world and doesn't use the ERPN
 			 * bits.
 			 */
-			ranges = <00000000 0 00000000 80000000
-			          80000000 0 80000000 80000000>;
+			ranges = <0x00000000 0x0 0x00000000 0x80000000
+			          0x80000000 0x0 0x80000000 0x80000000>;
 			/* interrupt-parent = <&UIC1>; */
 			interrupts = <7 4>;
-			clock-frequency = <03f940aa>;
+			clock-frequency = <0x03f940aa>;
 
 			EBC0: ebc {
 				compatible = "ibm,ebc-440ep", "ibm,ebc-440gp", "ibm,ebc";
-				dcr-reg = <012 2>;
+				dcr-reg = <0x012 2>;
 				#address-cells = <2>;
 				#size-cells = <1>;
-				clock-frequency = <03f940aa>;
+				clock-frequency = <0x03f940aa>;
 				interrupts = <5 1>;
 			/* interrupt-parent = <&UIC1>; */
 			};
@@ -121,10 +110,10 @@
 			UART0: serial at ef600300 {
 				device_type = "serial";
 				compatible = "ns16550";
-				reg = <ef600300 8>;
-				virtual-reg = <ef600300>;
-				clock-frequency = <00a8c000>;
-				current-speed = <1c200>;
+				reg = <0xef600300 8>;
+				virtual-reg = <0xef600300>;
+				clock-frequency = <0x00a8c000>;
+				current-speed = <0x1c200>;
 				interrupt-parent = <&UIC0>;
 				interrupts = <0 4>;
 			};
@@ -132,41 +121,18 @@
 			UART1: serial at ef600400 {
 				device_type = "serial";
 				compatible = "ns16550";
-				reg = <ef600400 8>;
-				virtual-reg = <ef600400>;
-				clock-frequency = <00a8c000>;
+				reg = <0xef600400 8>;
+				virtual-reg = <0xef600400>;
+				clock-frequency = <0x00a8c000>;
 				current-speed = <0>;
 				interrupt-parent = <&UIC0>;
 				interrupts = <1 4>;
 			};
-/*
-			UART2: serial at ef600500 {
-				device_type = "serial";
-				compatible = "ns16550";
-				reg = <ef600500 8>;
-				virtual-reg = <ef600500>;
-				clock-frequency = <0>;
-				current-speed = <0>;
-				interrupt-parent = <&UIC0>;
-				interrupts = <3 4>;
-			};
-
-			UART3: serial at ef600600 {
-				device_type = "serial";
-				compatible = "ns16550";
-				reg = <ef600600 8>;
-				virtual-reg = <ef600600>;
-				clock-frequency = <0>;
-				current-speed = <0>;
-				interrupt-parent = <&UIC0>;
-				interrupts = <4 4>;
-			};
 
-*/
 			IIC0: i2c at ef600700 {
 				device_type = "i2c";
 				compatible = "ibm,iic-440ep", "ibm,iic-440gp", "ibm,iic";
-				reg = <ef600700 14>;
+				reg = <0xef600700 0x14>;
 				interrupt-parent = <&UIC0>;
 				interrupts = <2 4>;
 			};
@@ -174,7 +140,7 @@
 			IIC1: i2c at ef600800 {
 				device_type = "i2c";
 				compatible = "ibm,iic-440ep", "ibm,iic-440gp", "ibm,iic";
-				reg = <ef600800 14>;
+				reg = <0xef600800 14>;
 				interrupt-parent = <&UIC0>;
 				interrupts = <7 4>;
 			};
@@ -182,7 +148,7 @@
 			ZMII0: emac-zmii at ef600d00 {
 				device_type = "zmii-interface";
 				compatible = "ibm,zmii-440ep", "ibm,zmii-440gp", "ibm,zmii";
-				reg = <ef600d00 c>;
+				reg = <0xef600d00 0xc>;
 			};
 
 		};
@@ -194,35 +160,35 @@
 			#address-cells = <3>;
 			compatible = "ibm,plb440ep-pci", "ibm,plb-pci";
 			primary;
-			reg = <0 eec00000 8     /* Config space access */
-			       0 eed00000 4     /* IACK */
-			       0 eed00000 4     /* Special cycle */
-			       0 ef400000 40>;  /* Internal registers */
+			reg = <0 0xeec00000 8     /* Config space access */
+			       0 0xeed00000 4     /* IACK */
+			       0 0xeed00000 4     /* Special cycle */
+			       0 0xef400000 0x40>;  /* Internal registers */
 
 			/* Outbound ranges, one memory and one IO,
 			 * later cannot be changed. Chip supports a second
 			 * IO range but we don't use it for now
 			 */
-			ranges = <02000000 0 a0000000 0 a0000000 0 20000000
-				  01000000 0 00000000 0 e8000000 0 00010000>;
+			ranges = <0x02000000 0 0xa0000000 0 0xa0000000 0 0x20000000
+				  0x01000000 0 0x00000000 0 0xe8000000 0 0x00010000>;
 
 			/* Inbound 2GB range starting at 0 */
-			dma-ranges = <42000000 0 0 0 0 0 80000000>;
+			dma-ranges = <0x42000000 0 0 0 0 0 0x80000000>;
 
 			/* Bamboo has all 4 IRQ pins tied together per slot */
-			interrupt-map-mask = <f800 0 0 0>;
+			interrupt-map-mask = <0xf800 0 0 0>;
 			interrupt-map = <
 				/* IDSEL 1 */
-				0800 0 0 0 &UIC0 1c 8
+				0x0800 0 0 0 &UIC0 0x1c 8
 
 				/* IDSEL 2 */
-				1000 0 0 0 &UIC0 1b 8
+				0x1000 0 0 0 &UIC0 0x1b 8
 
 				/* IDSEL 3 */
-				1800 0 0 0 &UIC0 1a 8
+				0x1800 0 0 0 &UIC0 0x1a 8
 
 				/* IDSEL 4 */
-				2000 0 0 0 &UIC0 19 8
+				0x2000 0 0 0 &UIC0 0x19 8
 			>;
 		};
 
commit d49bc1fb3e2ca981e1655b82cbd5ef6b301ce2ff
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 3 19:15:16 2012 +0100

    PPC: 440: Ignore invalid PCI IRQs
    
    When running a 440 target, we currently get invalid irq_num values (-1)
    which completely confuse the IRQ setting code.
    
    This is most likely due to the missing qdev conversion.
    
    While this shouldn't happen in the first place and should really rather
    be fixed by converting the target, I dislike segfaults. So for now, let's
    just print a warning and ignore invalid irq_num values.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index 2c69210..1bf785b 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -275,6 +275,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);
 }
 
commit 72718e9a4a26f18ba765b4954e5be985676a60b8
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 3 19:12:47 2012 +0100

    PPC: Bamboo: Set initial TLB entry
    
    Back in the day when the bamboo target got introduced, the initial TLB was
    dictated by KVM. TCG has been missing initial TLB values ever since, rendering
    the target unusable for TCG usage.
    
    This patch adds linear TLB maps the way Linux expects them, making the target
    work.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index f82d587..c17f6f7 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -103,6 +103,29 @@ 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;
@@ -111,6 +134,9 @@ static void main_cpu_reset(void *opaque)
     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,
@@ -181,7 +207,6 @@ static void bamboo_init(ram_addr_t ram_size,
             fprintf(stderr, "couldn't load device tree\n");
             exit(1);
         }
-        /* XXX we currently depend on KVM to create some initial TLB entries. */
     }
 
     if (kvm_enabled())
commit b10a04b5aeca558a9f306ae749fd87850ad8d973
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 3 19:10:02 2012 +0100

    PPC: Bamboo: Register CPU reset
    
    To be able to support CPU reset, we need to put all register initialization
    and initial state into a CPU reset hook instead of a function that is only
    called once on bootup.
    
    This is a preparation step for the initial TLB setting code and brings bamboo
    more in line with what e500 and virtex already do.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index b734e3a..f82d587 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -32,6 +32,8 @@
 #define FDT_ADDR     0x1800000
 #define RAMDISK_ADDR 0x1900000
 
+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 +103,16 @@ out:
     return ret;
 }
 
+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;
+}
+
 static void bamboo_init(ram_addr_t ram_size,
                         const char *boot_device,
                         const char *kernel_filename,
@@ -114,7 +126,6 @@ static void bamboo_init(ram_addr_t ram_size,
     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;
     int success;
@@ -123,6 +134,7 @@ static void bamboo_init(ram_addr_t ram_size,
     /* Setup CPU. */
     env = ppc440ep_init(address_space_mem, &ram_size, &pcibus,
                         pci_irq_nrs, 1, cpu_model);
+    qemu_register_reset(main_cpu_reset, env);
 
     if (pcibus) {
         /* Register network interfaces. */
@@ -169,11 +181,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. */
     }
 
commit d29d3404fc1bb9e47b0e1cdc16218a574fbc2754
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Jan 3 18:55:38 2012 +0100

    PPC: 440EP: Initialize timer
    
    When using TCG with a BookE PowerPC core, we need to explicitly initialize
    the BookE timers with the correct frequencies.
    
    This was missing for 440EP, since that code came from KVM and was never used
    with TCG.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc440.c b/hw/ppc440.c
index cd8a95d..f7779bf 100644
--- a/hw/ppc440.c
+++ b/hw/ppc440.c
@@ -56,6 +56,7 @@ CPUState *ppc440ep_init(MemoryRegion *address_space_mem, ram_addr_t *ram_size,
         exit(1);
     }
 
+    ppc_booke_timers_init(env, 400000000, 0);
     ppc_dcr_init(env, NULL, NULL);
 
     /* interrupt controller */
commit 506b7ddf889312659b36c667f7ae17bc9e909418
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Mon Jan 9 02:04:05 2012 +0100

    prep: Use i82378 PCI->ISA bridge for 'prep' machine
    
    Speaker I/O, ISA bus, i8259 PIC, RTC and DMA are no longer set up
    individually by the machine. Effectively, no-op speaker I/O is replaced
    by pcspk; PIT and i82374 DMA are introduced.
    
    Signed-off-by: Hervé Poussineau <hpoussin at reactos.org>
    
    Remove related dead, alternative code.
    Wire up PCI host bridge IRQs via GPIO-in IRQs of PCI->ISA bridge.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Cc: Alexander Graf <agraf at suse.de>
    Cc: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 62d0e36..438a75d 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -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,
@@ -526,8 +498,8 @@ static void ppc_prep_init (ram_addr_t ram_size,
     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];
@@ -629,13 +601,9 @@ 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]);
 
     dev = qdev_create(NULL, "raven-pcihost");
     sys = sysbus_from_qdev(dev);
@@ -648,13 +616,19 @@ static void ppc_prep_init (ram_addr_t ram_size,
         fprintf(stderr, "Couldn't create PCI host controller.\n");
         exit(1);
     }
-    sysbus_connect_irq(&pcihost->busdev, 0, i8259[9]);
-    sysbus_connect_irq(&pcihost->busdev, 1, i8259[11]);
-    sysbus_connect_irq(&pcihost->busdev, 2, i8259[9]);
-    sysbus_connect_irq(&pcihost->busdev, 3, i8259[11]);
 
-    isa_bus_irqs(isa_bus, i8259);
-    //    pci_bus = i440fx_init();
+    /* 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);
@@ -662,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]);
@@ -691,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++) {
@@ -701,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);
commit a04ff940974a49c540250426c7c7488c93b0e48f
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Sat Dec 25 06:01:41 2010 +0100

    prep: Add i82378 PCI-to-ISA bridge emulation
    
    Prepare Intel 82378 emulation for use by PReP platforms.
    
    Signed-off-by: Hervé Poussineau <hpoussin at reactos.org>
    
    Create ISA bus in this device (suggested by Markus).
    Rebase onto Memory API, mark memory ops as Little Endian.
    Add VMState. Provide access to i8259 IRQs via qdev GPIOs.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Cc: Markus Armbruster <armbru at redhat.com>
    Cc: Alexander Graf <agraf at suse.de>
    Cc: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/Makefile.objs b/Makefile.objs
index 701c23c..0b55f34 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -226,6 +226,7 @@ hw-obj-$(CONFIG_I8259) += i8259.o
 
 # PPC devices
 hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o
+hw-obj-$(CONFIG_I82378) += i82378.o
 # Mac shared devices
 hw-obj-$(CONFIG_MACIO) += macio.o
 hw-obj-$(CONFIG_CUDA) += cuda.o
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index e5905d5..1fe9c6d 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -14,7 +14,9 @@ CONFIG_DMA=y
 CONFIG_I82374=y
 CONFIG_OPENPIC=y
 CONFIG_PREP_PCI=y
+CONFIG_I82378=y
 CONFIG_MACIO=y
+CONFIG_PCSPK=y
 CONFIG_CUDA=y
 CONFIG_ADB=y
 CONFIG_MAC_NVRAM=y
diff --git a/hw/i82378.c b/hw/i82378.c
new file mode 100644
index 0000000..95ae274
--- /dev/null
+++ b/hw/i82378.c
@@ -0,0 +1,264 @@
+/*
+ * 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 PCIDeviceInfo pci_i82378_info = {
+    .init = pci_i82378_init,
+    .qdev.name = "i82378",
+    .qdev.size = sizeof(PCIi82378State),
+    .qdev.vmsd = &vmstate_pci_i82378,
+    .vendor_id = PCI_VENDOR_ID_INTEL,
+    .device_id = PCI_DEVICE_ID_INTEL_82378,
+    .revision = 0x03,
+    .class_id = PCI_CLASS_BRIDGE_ISA,
+    .subsystem_vendor_id = 0x0,
+    .subsystem_id = 0x0,
+    .qdev.props = (Property[]) {
+        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 i82378_register_devices(void)
+{
+    pci_qdev_register(&pci_i82378_info);
+}
+
+device_init(i82378_register_devices)
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index 85e5372..e8235a7 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
commit 23b96cdb15b6a35bdf28f7092ac32982d29b4c6c
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Sat Dec 25 05:29:37 2010 +0100

    prep: Add i82374 DMA emulation
    
    Prepare Intel 82374 emulation for use by Intel 82378 PCI->ISA bridge.
    
    Signed-off-by: Hervé Poussineau <hpoussin at reactos.org>
    
    Confine to CONFIG_I82374. Add VMState.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Reviewed-by: Alexander Graf <agraf at suse.de>

diff --git a/Makefile.objs b/Makefile.objs
index f94c881..701c23c 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -216,6 +216,7 @@ hw-obj-$(CONFIG_FDC) += fdc.o
 hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
 hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o
 hw-obj-$(CONFIG_DMA) += dma.o
+hw-obj-$(CONFIG_I82374) += i82374.o
 hw-obj-$(CONFIG_HPET) += hpet.o
 hw-obj-$(CONFIG_APPLESMC) += applesmc.o
 hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o ccid-card-passthru.o
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index c85cdce..e5905d5 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -11,6 +11,7 @@ CONFIG_I8254=y
 CONFIG_PCKBD=y
 CONFIG_FDC=y
 CONFIG_DMA=y
+CONFIG_I82374=y
 CONFIG_OPENPIC=y
 CONFIG_PREP_PCI=y
 CONFIG_MACIO=y
diff --git a/hw/i82374.c b/hw/i82374.c
new file mode 100644
index 0000000..616d1fc
--- /dev/null
+++ b/hw/i82374.c
@@ -0,0 +1,154 @@
+/*
+ * 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 ISADeviceInfo i82374_isa_info = {
+    .qdev.name  = "i82374",
+    .qdev.size  = sizeof(ISAi82374State),
+    .qdev.vmsd  = &vmstate_isa_i82374,
+    .init       = i82374_isa_init,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_HEX32("iobase", ISAi82374State, iobase, 0x400),
+        DEFINE_PROP_END_OF_LIST()
+    },
+};
+
+static void i82374_register_devices(void)
+{
+    isa_qdev_register(&i82374_isa_info);
+}
+
+device_init(i82374_register_devices)
commit 1c75457fd5cb97482d0d0ab537adf688ea06750b
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Sat Jan 7 00:12:15 2012 +0100

    MAINTAINERS: Add PCI host bridge files to PReP machine
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Acked-by: Alexander Graf <agraf at suse.de>

diff --git a/MAINTAINERS b/MAINTAINERS
index de2a916..148f0d2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -307,6 +307,7 @@ PReP
 M: Andreas Färber <andreas.faerber at web.de>
 S: Odd Fixes
 F: hw/ppc_prep.c
+F: hw/prep_pci.[hc]
 
 SH4 Machines
 ------------
commit 8ca8c7bce027d0f4aaa8ca108ebae37021361b98
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Tue Jan 3 02:42:46 2012 +0100

    prep: qdev'ify Raven host bridge (SysBus)
    
    Drop pci_prep_init() in favor of extended device state. Inspired by
    patches from Hervé and Alex.
    
    Assign the 4 IRQs from the board after device instantiation. This moves
    the knowledge out of prep_pci and allows for future machines with
    different IRQ wiring (IBM 40P). Suggested by Alex.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Reviewed-by: Alexander Graf <agraf at suse.de>
    Cc: Hervé Poussineau <hpoussin at reactos.org>
    Cc: Michael S. Tsirkin <mst at redhat.com>
    Cc: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 1cc0ae0..62d0e36 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"
@@ -522,6 +522,9 @@ 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;
     ISABus *isa_bus;
     qemu_irq *i8259;
@@ -633,7 +636,23 @@ static void ppc_prep_init (ram_addr_t ram_size,
     /* 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());
+
+    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);
+    qdev_property_add_child(qdev_get_root(), "raven", 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);
+    }
+    sysbus_connect_irq(&pcihost->busdev, 0, i8259[9]);
+    sysbus_connect_irq(&pcihost->busdev, 1, i8259[11]);
+    sysbus_connect_irq(&pcihost->busdev, 2, i8259[9]);
+    sysbus_connect_irq(&pcihost->busdev, 3, i8259[11]);
+
     isa_bus_irqs(isa_bus, i8259);
     //    pci_bus = i440fx_init();
     /* Register 8 MB of ISA IO space (needed for non-contiguous map) */
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index 2600e26..4961eed 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -25,9 +25,12 @@
 #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;
@@ -48,14 +51,14 @@ static void ppc_pci_io_write(void *opaque, target_phys_addr_t addr,
                              uint64_t val, unsigned int size)
 {
     PREPPCIState *s = opaque;
-    pci_data_write(s->bus, PPC_PCIIO_config(addr), val, size);
+    pci_data_write(s->host_state.bus, PPC_PCIIO_config(addr), val, size);
 }
 
 static uint64_t ppc_pci_io_read(void *opaque, target_phys_addr_t addr,
                                 unsigned int size)
 {
     PREPPCIState *s = opaque;
-    return pci_data_read(s->bus, PPC_PCIIO_config(addr), size);
+    return pci_data_read(s->host_state.bus, PPC_PCIIO_config(addr), size);
 }
 
 static const MemoryRegionOps PPC_PCIIO_ops = {
@@ -73,38 +76,43 @@ 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;
+    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);
+    sysbus_add_io(dev, 0xcfc, &h->data_mem);
+    sysbus_init_ioports(&h->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);
+    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(s->bus, 0, "raven");
+    pci_create_simple(bus, 0, "raven");
 
-    return s->bus;
+    return 0;
 }
 
 static int raven_init(PCIDevice *d)
@@ -143,8 +151,17 @@ static PCIDeviceInfo raven_info = {
     },
 };
 
+static SysBusDeviceInfo raven_pcihost_info = {
+    .qdev.name = "raven-pcihost",
+    .qdev.fw_name = "pci",
+    .qdev.size = sizeof(PREPPCIState),
+    .qdev.no_user = 1,
+    .init = raven_pcihost_init,
+};
+
 static void raven_register_devices(void)
 {
+    sysbus_register_withprop(&raven_pcihost_info);
     pci_qdev_register(&raven_info);
 }
 
diff --git a/hw/prep_pci.h b/hw/prep_pci.h
deleted file mode 100644
index b6b481a..0000000
--- 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
commit 7e5610ff72b0d12feb24d1e973e4be303f422eb6
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Sat Jan 7 08:28:53 2012 +0100

    prep_pci: Update I/O to MemoryRegion ops
    
    Convert to new-style read/write callbacks.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Cc: Alexander Graf <agraf at suse.de>
    Cc: Michael S. Tsirkin <mst at redhat.com>
    Cc: Avi Kivity <avi at redhat.com>
    Cc: Benoît Canet <benoit.canet at gmail.com>

diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index edfb25d..2600e26 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -44,53 +44,23 @@ 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)
+static void ppc_pci_io_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t val, unsigned int size)
 {
     PREPPCIState *s = opaque;
-    pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 1);
+    pci_data_write(s->bus, PPC_PCIIO_config(addr), val, size);
 }
 
-static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val)
+static uint64_t ppc_pci_io_read(void *opaque, target_phys_addr_t addr,
+                                unsigned int size)
 {
     PREPPCIState *s = opaque;
-    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)
-{
-    PREPPCIState *s = opaque;
-    pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 4);
-}
-
-static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr)
-{
-    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);
-    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);
-    return val;
+    return pci_data_read(s->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, },
-    },
+    .read = ppc_pci_io_read,
+    .write = ppc_pci_io_write,
     .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
commit 9c95f183fbac16dfaefab4a023e80fdfae273a76
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Thu Jan 12 03:44:42 2012 +0100

    prep_pci: Simplify I/O endianness
    
    The prep PowerPC CPU is Big Endian. An explicit byte swap therefore
    effectively becomes Little Endian.
    
    Remove explicit byte swaps and mark as Little Endian.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Reviewed-by: Alexander Graf <agraf at suse.de>
    Cc: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index 741b273..edfb25d 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -53,14 +53,12 @@ static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t va
 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)
 {
     PREPPCIState *s = opaque;
-    val = bswap32(val);
     pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 4);
 }
 
@@ -77,7 +75,6 @@ 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;
 }
 
@@ -86,7 +83,6 @@ 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;
 }
 
@@ -95,7 +91,7 @@ static const MemoryRegionOps PPC_PCIIO_ops = {
         .read = { PPC_PCIIO_readb, PPC_PCIIO_readw, PPC_PCIIO_readl, },
         .write = { PPC_PCIIO_writeb, PPC_PCIIO_writew, PPC_PCIIO_writel, },
     },
-    .endianness = DEVICE_NATIVE_ENDIAN,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 static int prep_map_irq(PCIDevice *pci_dev, int irq_num)
commit 555260540dc5a1988aed94a1aa2291bb5f947dac
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Tue Jan 3 01:50:07 2012 +0100

    prep: qdev'ify Raven host bridge (PCIDevice)
    
    Move initialization of vendor ID, etc. to PCIDeviceInfo.
    Introduce VMState.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Reviewed-by: Alexander Graf <agraf at suse.de>
    Cc: Hervé Poussineau <hpoussin at reactos.org>
    Cc: Michael S. Tsirkin <mst at redhat.com>
    Cc: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index ea9fb69..741b273 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -29,6 +29,10 @@
 
 typedef PCIHostState PREPPCIState;
 
+typedef struct RavenPCIState {
+    PCIDevice dev;
+} RavenPCIState;
+
 static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr)
 {
     int i;
@@ -111,7 +115,6 @@ PCIBus *pci_prep_init(qemu_irq *pic,
                       MemoryRegion *address_space_io)
 {
     PREPPCIState *s;
-    PCIDevice *d;
 
     s = g_malloc0(sizeof(PREPPCIState));
     s->bus = pci_register_bus(NULL, "pci",
@@ -133,16 +136,50 @@ PCIBus *pci_prep_init(qemu_irq *pic,
     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);
+    pci_create_simple(s->bus, 0, "raven");
+
+    return s->bus;
+}
+
+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 PCIDeviceInfo raven_info = {
+    .qdev.name = "raven",
+    .qdev.desc = "PReP Host Bridge - Motorola Raven",
+    .qdev.size = sizeof(RavenPCIState),
+    .qdev.vmsd = &vmstate_raven,
+    .qdev.no_user = 1,
+    .no_hotplug = 1,
+    .init = raven_init,
+    .vendor_id = PCI_VENDOR_ID_MOTOROLA,
+    .device_id = PCI_DEVICE_ID_MOTOROLA_RAVEN,
+    .revision = 0x00,
+    .class_id = PCI_CLASS_BRIDGE_HOST,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_END_OF_LIST()
+    },
+};
+
+static void raven_register_devices(void)
+{
+    pci_qdev_register(&raven_info);
+}
+
+device_init(raven_register_devices)
commit 48e937283af85aedb7d974a774c7c6bf21794b24
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Fri Jan 13 18:03:48 2012 +0100

    prep: Use ISA m48t59
    
    This simplifies the code later when the i8259 moves to the i82378
    PCI->ISA bridge and happens to fix a SysBus m48t59 io_base issue
    introduced by commit 0fb56ffc5edd66f12ccfc0d71af5f9c79c0a2612 (m48t59:
    drop obsolete address base arithmetic). Suggested by Hervé and Jan.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Cc: Hervé Poussineau <hpoussin at reactos.org>
    Cc: Jan Kiszka <jan.kiszka at siemens.com>
    Cc: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index dec059a..1cc0ae0 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -707,7 +707,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;
commit 809680c017b944676a34d2712560da61895f4a6d
Author: Andreas Färber <afaerber at suse.de>
Date:   Thu Jan 5 16:48:23 2012 +0100

    prep: Fix offset of BIOS MemoryRegion
    
    Since 0c90c52fab5ea92d7f12b29bfe26a7cd75d9efcb (ppc_prep: convert to memory
    API) OHW was "Trying to execute code outside RAM or ROM at 0xfff00700".
    
    The BIOS MemoryRegion is created with a fixed size of 1 MiB.
    Ensure that the full size can be accessed since the exception
    vectors are located at 0xfff00000 and the BIOS may want to use them.
    
    It thereby no longer depends on the actual BIOS binary size.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Cc: Avi Kivity <avi at redhat.com>
    Cc: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 47dab3f..dec059a 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -560,6 +560,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 +575,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) {
commit 515689235c4c3d9c3f0406ddcdd21ed8da77062b
Merge: a75e667... 6b7332e...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Jan 19 12:51:02 2012 -0600

    Merge remote-tracking branch 'spice/spice.v47' into staging
    
    * spice/spice.v47:
      qxl: Slot sanity check in qxl_phys2virt() is off by one, fix

commit a75e6678fe095147c7343ec9d0e772ae640f0e7a
Merge: b48c013... dcfa486...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Jan 19 09:23:59 2012 -0600

    Merge remote-tracking branch 'stefanha/trivial-patches' into staging
    
    * stefanha/trivial-patches:
      Makefile: Remove generated headers on clean
      Makefile: Exclude tests/Makefile in unconfigured tree
      lm32: Fix mixup of uint32 and uint32_t
      tests: Silence gtester in Makefile
      qemu-tool: Fix mixup of int64 and int64_t

commit b48c0134de96f3deed15a0e115d58f3cff09f3c1
Merge: 5414b32... 939a1cc...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Jan 19 09:23:16 2012 -0600

    Merge remote-tracking branch 'qmp/queue/qmp' into staging
    
    * qmp/queue/qmp:
      block: use proper qerrors in qmp_block_resize
      qerror: restore alphabetical order over qerrors
      qerror: add check-qerror.sh to verify alphabetical order
      qmp: Add missing gcc format attribute and fix format string
      qapi: Convert block_set_io_throttle
      qapi: Convert change
      qerror: Extend QERR_DEVICE_ENCRYPTED
      qapi: Introduce change-vnc-password
      monitor: expose readline state
      qapi: Convert eject
      block: eject_device(): Use error_set()
      qapi: Convert expire_password
      qapi: Convert set_password
      vnc: Simplify vnc_display_password()

commit 5414b32542662976c364b58011c4841304569aff
Merge: 9ca2140... a32134a...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Jan 19 09:19:44 2012 -0600

    Merge remote-tracking branch 'pmaydell/arm-devs.for-upstream' into staging
    
    * pmaydell/arm-devs.for-upstream:
      arm: make the number of GIC interrupts configurable
      hw/lan9118: Add save/load support
      arm: Remove incorrect comment in arm_timer
      vexpress, realview: Add (dummy) L2 cache controller

commit 9ca2140ab10a9fde4e60fb9499a733932d30386f
Merge: 8c4ec5c... 3221354...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Jan 19 08:34:38 2012 -0600

    Merge remote-tracking branch 'kraxel/usb.37' into staging
    
    * kraxel/usb.37:
      usb-redir: Improve some debugging messages
      usb-redir: Try to keep our buffer size near the target size
      usb-redir: Pre-fill our isoc input buffer before sending pkts to the host
      usb-redir: Dynamically adjust iso buffering size based on ep interval
      usb-redir: Clear iso / irq error when stopping the stream
      usb: link packets to endpoints not devices
      usb: add max_packet_size to USBEndpoint
      usb/debug: add usb_ep_dump
      usb-desc: USBEndpoint support
      usb: add ifnum to USBEndpoint
      usb: add USBEndpoint
      xhci: Initial xHCI implementation
      usb: add audio device model
      usb-desc: audio endpoint support
      usb: track altsetting in USBDevice
      usb: track configuration and interface count in USBDevice.
      usb-host: rip out legacy procfs support

commit 6a48ffaaa732b2142c1b5030178f2d4a0fa499fe
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Oct 15 13:43:48 2011 +0200

    kvm: Activate in-kernel irqchip support
    
    Make the basic in-kernel irqchip support selectable via
    -machine ...,kernel_irqchip=on. Leave it off by default until it can
    fully replace user space models.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/qemu-config.c b/qemu-config.c
index ecc88e8..b030205 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -531,6 +531,10 @@ static QemuOptsList qemu_machine_opts = {
             .name = "accel",
             .type = QEMU_OPT_STRING,
             .help = "accelerator list",
+        }, {
+            .name = "kernel_irqchip",
+            .type = QEMU_OPT_BOOL,
+            .help = "use KVM in-kernel irqchip",
         },
         { /* End of list */ }
     },
diff --git a/qemu-options.hx b/qemu-options.hx
index 6295cde..3a07ae8 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -31,7 +31,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
     "-machine [type=]name[,prop[=value][,...]]\n"
     "                selects emulated machine (-machine ? for list)\n"
     "                property accel=accel1[:accel2[:...]] selects accelerator\n"
-    "                supported accelerators are kvm, xen, tcg (default: tcg)\n",
+    "                supported accelerators are kvm, xen, tcg (default: tcg)\n"
+    "                kernel_irqchip=on|off controls accelerated irqchip support\n",
     QEMU_ARCH_ALL)
 STEXI
 @item -machine [type=]@var{name}[,prop=@var{value}[,...]]
@@ -44,6 +45,8 @@ This is used to enable an accelerator. Depending on the target architecture,
 kvm, xen, or tcg can be available. By default, tcg is used. If there is more
 than one accelerator specified, the next one is used if the previous one fails
 to initialize.
+ at item kernel_irqchip=on|off
+Enables in-kernel irqchip support for the chosen accelerator when available.
 @end table
 ETEXI
 
commit a39c1d47ac970312333bb93456e249e965315490
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sun Oct 16 23:25:49 2011 +0200

    kvm: x86: Add user space part for in-kernel IOAPIC
    
    This introduces the KVM-accelerated IOAPIC model 'kvm-ioapic' and
    extends the IRQ routing setup by the 0->2 redirection when needed.
    
    The kvm-ioapic model has a property that allows to define its GSI base
    for injecting interrupts into the kernel model. This will allow to
    disentangle PIC and IOAPIC pins for chipsets that support more
    sophisticated IRQ routes than the PIIX3. So far the base is kept at 0,
    i.e. PIC and IOAPIC share pins 0..15.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/Makefile.target b/Makefile.target
index 701073d..98cb997 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -233,7 +233,7 @@ obj-i386-y += vmport.o
 obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
-obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o
+obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c
new file mode 100644
index 0000000..10ffdd4
--- /dev/null
+++ b/hw/kvm/ioapic.c
@@ -0,0 +1,114 @@
+/*
+ * KVM in-kernel IOPIC support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka at 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 IOAPICCommonInfo kvm_ioapic_info = {
+    .busdev.qdev.name  = "kvm-ioapic",
+    .busdev.qdev.size = sizeof(KVMIOAPICState),
+    .busdev.qdev.reset = kvm_ioapic_reset,
+    .busdev.qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0),
+        DEFINE_PROP_END_OF_LIST()
+    },
+    .init      = kvm_ioapic_init,
+    .pre_save  = kvm_ioapic_get,
+    .post_load = kvm_ioapic_put,
+};
+
+static void kvm_ioapic_register_device(void)
+{
+    ioapic_qdev_register(&kvm_ioapic_info);
+}
+
+device_init(kvm_ioapic_register_device)
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 297c04a..a285ad2 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -69,6 +69,15 @@ static void kvm_piix3_setup_irq_routing(bool pci_enabled)
         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");
@@ -95,7 +104,11 @@ static void ioapic_init(GSIState *gsi_state)
     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);
commit 10b618827507fbdbe7cf1a9b1f2c81d254dcd8b8
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sun Oct 16 15:30:27 2011 +0200

    kvm: x86: Add user space part for in-kernel i8259
    
    Introduce the alternative 'kvm-i8259' device model that exploits KVM
    in-kernel acceleration.
    
    The PIIX3 initialization code is furthermore extended by KVM specific
    IRQ route setup. GSI injection differs in KVM mode from the user space
    model. As we can dispatch ISA-range IRQs to both IOAPIC and PIC inside
    the kernel, we do not need to inject them separately. This is reflected
    by a KVM-specific GSI handler.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/Makefile.target b/Makefile.target
index 1a63a1c..701073d 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -233,7 +233,7 @@ obj-i386-y += vmport.o
 obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
-obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o
+obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c
new file mode 100644
index 0000000..64bb5c2
--- /dev/null
+++ b/hw/kvm/i8259.c
@@ -0,0 +1,128 @@
+/*
+ * KVM in-kernel PIC (i8259) support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka at 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 PICCommonInfo kvm_i8259_info = {
+    .isadev.qdev.name  = "kvm-i8259",
+    .isadev.qdev.reset = kvm_pic_reset,
+    .init       = kvm_pic_init,
+    .pre_save   = kvm_pic_get,
+    .post_load  = kvm_pic_put,
+};
+
+static void kvm_pic_register(void)
+{
+    pic_qdev_register(&kvm_i8259_info);
+}
+
+device_init(kvm_pic_register)
diff --git a/hw/pc.h b/hw/pc.h
index ece069a..5e913db 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -64,6 +64,7 @@ bool parallel_mm_init(MemoryRegion *address_space,
 
 extern DeviceState *isa_pic;
 qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq);
+qemu_irq *kvm_i8259_init(ISABus *bus);
 int pic_read_irq(DeviceState *d);
 int pic_get_output(DeviceState *d);
 void pic_info(Monitor *mon);
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index cde810d..297c04a 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -53,6 +53,42 @@ 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);
+        }
+        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;
@@ -134,7 +170,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 +196,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++) {
commit 680c1c6fd73c0cb3971938944936f18bbb7bad1b
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sun Oct 16 13:23:26 2011 +0200

    kvm: x86: Add user space part for in-kernel APIC
    
    This introduces the alternative APIC device which makes use of KVM's
    in-kernel device model. External NMI injection via LINT1 is emulated by
    checking the current state of the in-kernel APIC, only injecting a NMI
    into the VCPU if LINT1 is unmasked and configured to DM_NMI.
    
    MSI is not yet supported, so we disable this when the in-kernel model is
    in use.
    
    CC: Lai Jiangshan <laijs at cn.fujitsu.com>
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/Makefile.target b/Makefile.target
index 556942d..1a63a1c 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -233,7 +233,7 @@ obj-i386-y += vmport.o
 obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
-obj-i386-$(CONFIG_KVM) += kvm/clock.o
+obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c
new file mode 100644
index 0000000..6300695
--- /dev/null
+++ b/hw/kvm/apic.c
@@ -0,0 +1,138 @@
+/*
+ * KVM in-kernel APIC support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka at 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 APICCommonInfo kvm_apic_info = {
+    .busdev.qdev.name = "kvm-apic",
+    .init = kvm_apic_init,
+    .set_base = kvm_apic_set_base,
+    .set_tpr = kvm_apic_set_tpr,
+    .external_nmi = kvm_apic_external_nmi,
+};
+
+static void kvm_apic_register_device(void)
+{
+    apic_qdev_register(&kvm_apic_info);
+}
+
+device_init(kvm_apic_register_device)
diff --git a/hw/pc.c b/hw/pc.c
index 38d787a..6a8a871 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -879,25 +879,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;
     }
 
-    msi_supported = true;
+    /* KVM does not support MSI yet. */
+    if (!kvm_enabled() || !kvm_irqchip_in_kernel()) {
+        msi_supported = true;
+    }
 
     return dev;
 }
diff --git a/kvm.h b/kvm.h
index ad430fd..40b5ffc 100644
--- a/kvm.h
+++ b/kvm.h
@@ -31,6 +31,7 @@ extern int kvm_allowed;
 #endif
 
 struct kvm_run;
+struct kvm_lapic_state;
 
 typedef struct KVMCapabilityInfo {
     const char *name;
@@ -134,6 +135,9 @@ int kvm_irqchip_set_irq(KVMState *s, int irq, int level);
 void kvm_irqchip_add_route(KVMState *s, int gsi, int irqchip, int pin);
 int kvm_irqchip_commit_routes(KVMState *s);
 
+void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic);
+void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic);
+
 struct kvm_guest_debug;
 struct kvm_debug_exit_arch;
 
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index f6f4189..e41de39 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -1337,6 +1337,36 @@ static int kvm_get_mp_state(CPUState *env)
     return 0;
 }
 
+static int kvm_get_apic(CPUState *env)
+{
+    DeviceState *apic = env->apic_state;
+    struct kvm_lapic_state kapic;
+    int ret;
+
+    if (apic && kvm_enabled() && kvm_irqchip_in_kernel()) {
+        ret = kvm_vcpu_ioctl(env, KVM_GET_LAPIC, &kapic);
+        if (ret < 0) {
+            return ret;
+        }
+
+        kvm_get_apic_state(apic, &kapic);
+    }
+    return 0;
+}
+
+static int kvm_put_apic(CPUState *env)
+{
+    DeviceState *apic = env->apic_state;
+    struct kvm_lapic_state kapic;
+
+    if (apic && kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_put_apic_state(apic, &kapic);
+
+        return kvm_vcpu_ioctl(env, KVM_SET_LAPIC, &kapic);
+    }
+    return 0;
+}
+
 static int kvm_put_vcpu_events(CPUState *env, int level)
 {
     struct kvm_vcpu_events events;
@@ -1510,6 +1540,10 @@ int kvm_arch_put_registers(CPUState *env, int level)
         if (ret < 0) {
             return ret;
         }
+        ret = kvm_put_apic(env);
+        if (ret < 0) {
+            return ret;
+        }
     }
     ret = kvm_put_vcpu_events(env, level);
     if (ret < 0) {
@@ -1557,6 +1591,10 @@ int kvm_arch_get_registers(CPUState *env)
     if (ret < 0) {
         return ret;
     }
+    ret = kvm_get_apic(env);
+    if (ret < 0) {
+        return ret;
+    }
     ret = kvm_get_vcpu_events(env);
     if (ret < 0) {
         return ret;
commit 9b5b76d44930dc9266bb6d30862704cb3c86d2ca
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Oct 15 14:08:26 2011 +0200

    kvm: x86: Establish IRQ0 override control
    
    KVM is forced to disable the IRQ0 override when we run with in-kernel
    irqchip but without IRQ routing support of the kernel. Set the fwcfg
    value correspondingly. This aligns us with qemu-kvm.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/hw/pc.c b/hw/pc.c
index 04304e0..38d787a 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -39,6 +39,7 @@
 #include "msi.h"
 #include "sysbus.h"
 #include "sysemu.h"
+#include "kvm.h"
 #include "blockdev.h"
 #include "ui/qemu-spice.h"
 #include "memory.h"
@@ -609,7 +610,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)
diff --git a/kvm-all.c b/kvm-all.c
index fa9d92d..88f1156 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1307,6 +1307,11 @@ int kvm_has_gsi_routing(void)
     return kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING);
 }
 
+int kvm_allows_irq0_override(void)
+{
+    return !kvm_enabled() || !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
+}
+
 void kvm_setup_guest_memory(void *start, size_t size)
 {
     if (!kvm_has_sync_mmu()) {
diff --git a/kvm-stub.c b/kvm-stub.c
index 06064b9..6c2b06b 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -78,6 +78,11 @@ int kvm_has_many_ioeventfds(void)
     return 0;
 }
 
+int kvm_allows_irq0_override(void)
+{
+    return 1;
+}
+
 void kvm_setup_guest_memory(void *start, size_t size)
 {
 }
diff --git a/kvm.h b/kvm.h
index dd2d4f0..ad430fd 100644
--- a/kvm.h
+++ b/kvm.h
@@ -53,6 +53,8 @@ int kvm_has_xcrs(void);
 int kvm_has_many_ioeventfds(void);
 int kvm_has_gsi_routing(void);
 
+int kvm_allows_irq0_override(void);
+
 #ifdef NEED_CPU_H
 int kvm_init_vcpu(CPUState *env);
 
diff --git a/sysemu.h b/sysemu.h
index ddef2bb..caff268 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -102,7 +102,6 @@ extern int vga_interface_type;
 extern int graphic_width;
 extern int graphic_height;
 extern int graphic_depth;
-extern uint8_t irq0override;
 extern DisplayType display_type;
 extern const char *keyboard_layout;
 extern int win2k_install_hack;
diff --git a/vl.c b/vl.c
index ba55b35..132c387 100644
--- a/vl.c
+++ b/vl.c
@@ -218,7 +218,6 @@ int no_reboot = 0;
 int no_shutdown = 0;
 int cursor_hide = 1;
 int graphic_rotate = 0;
-uint8_t irq0override = 1;
 const char *watchdog;
 QEMUOptionRom option_rom[MAX_OPTION_ROMS];
 int nb_option_roms;
commit 84b058d7df1e75543ef7422d97b039cd413f68f1
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Oct 15 11:49:47 2011 +0200

    kvm: Introduce core services for in-kernel irqchip support
    
    Add the basic infrastructure to active in-kernel irqchip support, inject
    interrupts into these models, and maintain IRQ routes.
    
    Routing is optional and depends on the host arch supporting
    KVM_CAP_IRQ_ROUTING. When it's not available on x86, we looe the HPET as
    we can't route GSI0 to IOAPIC pin 2.
    
    In-kernel irqchip support will once be controlled by the machine
    property 'kernel_irqchip', but this is not yet wired up.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/kvm-all.c b/kvm-all.c
index 2cc4562..fa9d92d 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -78,6 +78,13 @@ struct KVMState
     int pit_in_kernel;
     int xsave, xcrs;
     int many_ioeventfds;
+    int irqchip_inject_ioctl;
+#ifdef KVM_CAP_IRQ_ROUTING
+    struct kvm_irq_routing *irq_routes;
+    int nr_allocated_irq_routes;
+    uint32_t *used_gsi_bitmap;
+    unsigned int max_gsi;
+#endif
 };
 
 KVMState *kvm_state;
@@ -728,6 +735,138 @@ static void kvm_handle_interrupt(CPUState *env, int mask)
     }
 }
 
+int kvm_irqchip_set_irq(KVMState *s, int irq, int level)
+{
+    struct kvm_irq_level event;
+    int ret;
+
+    assert(s->irqchip_in_kernel);
+
+    event.level = level;
+    event.irq = irq;
+    ret = kvm_vm_ioctl(s, s->irqchip_inject_ioctl, &event);
+    if (ret < 0) {
+        perror("kvm_set_irqchip_line");
+        abort();
+    }
+
+    return (s->irqchip_inject_ioctl == KVM_IRQ_LINE) ? 1 : event.status;
+}
+
+#ifdef KVM_CAP_IRQ_ROUTING
+static void set_gsi(KVMState *s, unsigned int gsi)
+{
+    assert(gsi < s->max_gsi);
+
+    s->used_gsi_bitmap[gsi / 32] |= 1U << (gsi % 32);
+}
+
+static void kvm_init_irq_routing(KVMState *s)
+{
+    int gsi_count;
+
+    gsi_count = kvm_check_extension(s, KVM_CAP_IRQ_ROUTING);
+    if (gsi_count > 0) {
+        unsigned int gsi_bits, i;
+
+        /* Round up so we can search ints using ffs */
+        gsi_bits = (gsi_count + 31) / 32;
+        s->used_gsi_bitmap = g_malloc0(gsi_bits / 8);
+        s->max_gsi = gsi_bits;
+
+        /* Mark any over-allocated bits as already in use */
+        for (i = gsi_count; i < gsi_bits; i++) {
+            set_gsi(s, i);
+        }
+    }
+
+    s->irq_routes = g_malloc0(sizeof(*s->irq_routes));
+    s->nr_allocated_irq_routes = 0;
+
+    kvm_arch_init_irq_routing(s);
+}
+
+static void kvm_add_routing_entry(KVMState *s,
+                                  struct kvm_irq_routing_entry *entry)
+{
+    struct kvm_irq_routing_entry *new;
+    int n, size;
+
+    if (s->irq_routes->nr == s->nr_allocated_irq_routes) {
+        n = s->nr_allocated_irq_routes * 2;
+        if (n < 64) {
+            n = 64;
+        }
+        size = sizeof(struct kvm_irq_routing);
+        size += n * sizeof(*new);
+        s->irq_routes = g_realloc(s->irq_routes, size);
+        s->nr_allocated_irq_routes = n;
+    }
+    n = s->irq_routes->nr++;
+    new = &s->irq_routes->entries[n];
+    memset(new, 0, sizeof(*new));
+    new->gsi = entry->gsi;
+    new->type = entry->type;
+    new->flags = entry->flags;
+    new->u = entry->u;
+
+    set_gsi(s, entry->gsi);
+}
+
+void kvm_irqchip_add_route(KVMState *s, int irq, int irqchip, int pin)
+{
+    struct kvm_irq_routing_entry e;
+
+    e.gsi = irq;
+    e.type = KVM_IRQ_ROUTING_IRQCHIP;
+    e.flags = 0;
+    e.u.irqchip.irqchip = irqchip;
+    e.u.irqchip.pin = pin;
+    kvm_add_routing_entry(s, &e);
+}
+
+int kvm_irqchip_commit_routes(KVMState *s)
+{
+    s->irq_routes->flags = 0;
+    return kvm_vm_ioctl(s, KVM_SET_GSI_ROUTING, s->irq_routes);
+}
+
+#else /* !KVM_CAP_IRQ_ROUTING */
+
+static void kvm_init_irq_routing(KVMState *s)
+{
+}
+#endif /* !KVM_CAP_IRQ_ROUTING */
+
+static int kvm_irqchip_create(KVMState *s)
+{
+    QemuOptsList *list = qemu_find_opts("machine");
+    int ret;
+
+    if (QTAILQ_EMPTY(&list->head) ||
+        !qemu_opt_get_bool(QTAILQ_FIRST(&list->head),
+                           "kernel_irqchip", false) ||
+        !kvm_check_extension(s, KVM_CAP_IRQCHIP)) {
+        return 0;
+    }
+
+    ret = kvm_vm_ioctl(s, KVM_CREATE_IRQCHIP);
+    if (ret < 0) {
+        fprintf(stderr, "Create kernel irqchip failed\n");
+        return ret;
+    }
+
+    s->irqchip_inject_ioctl = KVM_IRQ_LINE;
+    if (kvm_check_extension(s, KVM_CAP_IRQ_INJECT_STATUS)) {
+        s->irqchip_inject_ioctl = KVM_IRQ_LINE_STATUS;
+    }
+    s->irqchip_in_kernel = 1;
+
+    kvm_init_irq_routing(s);
+
+    return 0;
+}
+
 int kvm_init(void)
 {
     static const char upgrade_note[] =
@@ -823,6 +962,11 @@ int kvm_init(void)
         goto err;
     }
 
+    ret = kvm_irqchip_create(s);
+    if (ret < 0) {
+        goto err;
+    }
+
     kvm_state = s;
     memory_listener_register(&kvm_memory_listener);
 
@@ -1158,6 +1302,11 @@ int kvm_has_many_ioeventfds(void)
     return kvm_state->many_ioeventfds;
 }
 
+int kvm_has_gsi_routing(void)
+{
+    return kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING);
+}
+
 void kvm_setup_guest_memory(void *start, size_t size)
 {
     if (!kvm_has_sync_mmu()) {
diff --git a/kvm.h b/kvm.h
index c1de81a..dd2d4f0 100644
--- a/kvm.h
+++ b/kvm.h
@@ -51,6 +51,7 @@ int kvm_has_debugregs(void);
 int kvm_has_xsave(void);
 int kvm_has_xcrs(void);
 int kvm_has_many_ioeventfds(void);
+int kvm_has_gsi_routing(void);
 
 #ifdef NEED_CPU_H
 int kvm_init_vcpu(CPUState *env);
@@ -124,6 +125,13 @@ void kvm_arch_reset_vcpu(CPUState *env);
 int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr);
 int kvm_arch_on_sigbus(int code, void *addr);
 
+void kvm_arch_init_irq_routing(KVMState *s);
+
+int kvm_irqchip_set_irq(KVMState *s, int irq, int level);
+
+void kvm_irqchip_add_route(KVMState *s, int gsi, int irqchip, int pin);
+int kvm_irqchip_commit_routes(KVMState *s);
+
 struct kvm_guest_debug;
 struct kvm_debug_exit_arch;
 
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 1f56492..f6f4189 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -1939,3 +1939,14 @@ bool kvm_arch_stop_on_emulation_error(CPUState *env)
     return !(env->cr[0] & CR0_PE_MASK) ||
            ((env->segs[R_CS].selector  & 3) != 3);
 }
+
+void kvm_arch_init_irq_routing(KVMState *s)
+{
+    if (!kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
+        /* If kernel can't do irq routing, interrupt source
+         * override 0->2 cannot be set up as required by HPET.
+         * So we have to disable it.
+         */
+        no_hpet = 1;
+    }
+}
commit 1660e72d4fbbd87e34eb4017d7e7c0ff4e29ca84
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sun Oct 23 16:01:19 2011 +0200

    memory: Introduce memory_region_init_reservation
    
    Introduce a memory region type that can reserve I/O space. Such regions
    are useful for modeling I/O that is only handled outside of QEMU, i.e.
    in the context of an accelerator like KVM.
    
    Any access to such a region from QEMU is a bug, but could theoretically
    be triggered by guest code (DMA to reserved region). So only warning
    about such events once, then ignore them.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/memory.c b/memory.c
index 6201a37..68e5cdf 100644
--- a/memory.c
+++ b/memory.c
@@ -1049,6 +1049,42 @@ void memory_region_init_rom_device(MemoryRegion *mr,
     mr->ram_addr |= cpu_register_io_memory(mr);
 }
 
+static uint64_t invalid_read(void *opaque, target_phys_addr_t addr,
+                             unsigned size)
+{
+    MemoryRegion *mr = opaque;
+
+    if (!mr->warning_printed) {
+        fprintf(stderr, "Invalid read from memory region %s\n", mr->name);
+        mr->warning_printed = true;
+    }
+    return -1U;
+}
+
+static void invalid_write(void *opaque, target_phys_addr_t addr, uint64_t data,
+                          unsigned size)
+{
+    MemoryRegion *mr = opaque;
+
+    if (!mr->warning_printed) {
+        fprintf(stderr, "Invalid write to memory region %s\n", mr->name);
+        mr->warning_printed = true;
+    }
+}
+
+static const MemoryRegionOps reservation_ops = {
+    .read = invalid_read,
+    .write = invalid_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void memory_region_init_reservation(MemoryRegion *mr,
+                                    const char *name,
+                                    uint64_t size)
+{
+    memory_region_init_io(mr, &reservation_ops, mr, name, size);
+}
+
 void memory_region_destroy(MemoryRegion *mr)
 {
     assert(QTAILQ_EMPTY(&mr->subregions));
diff --git a/memory.h b/memory.h
index d48b08b..34c69cf 100644
--- a/memory.h
+++ b/memory.h
@@ -126,6 +126,7 @@ struct MemoryRegion {
     bool readonly; /* For RAM regions */
     bool enabled;
     bool rom_device;
+    bool warning_printed; /* For reservations */
     MemoryRegion *alias;
     target_phys_addr_t alias_offset;
     unsigned priority;
@@ -280,6 +281,21 @@ void memory_region_init_rom_device(MemoryRegion *mr,
                                    uint64_t size);
 
 /**
+ * memory_region_init_reservation: Initialize a memory region that reserves
+ *                                 I/O space.
+ *
+ * A reservation region primariy serves debugging purposes.  It claims I/O
+ * space that is not supposed to be handled by QEMU itself.  Any access via
+ * the memory API will cause an abort().
+ *
+ * @mr: the #MemoryRegion to be initialized
+ * @name: used for debugging; not visible to the user or ABI
+ * @size: size of the region.
+ */
+void memory_region_init_reservation(MemoryRegion *mr,
+                                    const char *name,
+                                    uint64_t size);
+/**
  * memory_region_destroy: Destroy a memory region and reclaim all resources.
  *
  * @mr: the region to be destroyed.  May not currently be a subregion
commit 244ac3af234fd636141182d60a007fcffd0970dc
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sun Oct 16 19:38:22 2011 +0200

    ioapic: Factor out base class for KVM reuse
    
    Split up the IOAPIC analogously to APIC and i8259. KVM will share the
    IOAPICCommonState, the vmstate, reset logic and certain init parts with
    the user space model.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/Makefile.target b/Makefile.target
index 4446273..556942d 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -228,7 +228,7 @@ obj-y += device-hotplug.o
 # Hardware support
 obj-i386-y += vga.o
 obj-i386-y += mc146818rtc.o pc.o
-obj-i386-y += cirrus_vga.o sga.o apic_common.o apic.o ioapic.o piix_pci.o
+obj-i386-y += cirrus_vga.o sga.o apic_common.o apic.o ioapic_common.o ioapic.o piix_pci.o
 obj-i386-y += vmport.o
 obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
diff --git a/hw/ioapic.c b/hw/ioapic.c
index 0743af6..0c8be50 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,71 +220,31 @@ ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val,
     }
 }
 
-static const VMStateDescription vmstate_ioapic = {
-    .name = "ioapic",
-    .version_id = 3,
-    .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);
 
-    ioapics[ioapic_no++] = s;
+    qdev_init_gpio_in(&s->busdev.qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
 
-    return 0;
+    ioapics[instance_no] = s;
 }
 
-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 IOAPICCommonInfo ioapic_info = {
+    .busdev.qdev.name = "ioapic",
+    .busdev.qdev.size = sizeof(IOAPICCommonState),
+    .busdev.qdev.reset = ioapic_reset_common,
+    .init = ioapic_init,
 };
 
 static void ioapic_register_devices(void)
 {
-    sysbus_register_withprop(&ioapic_info);
+    ioapic_qdev_register(&ioapic_info);
 }
 
 device_init(ioapic_register_devices)
diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c
new file mode 100644
index 0000000..3aa9a1c
--- /dev/null
+++ b/hw/ioapic_common.c
@@ -0,0 +1,104 @@
+/*
+ *  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 = DO_UPCAST(IOAPICCommonState, busdev.qdev, 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 = opaque;
+    IOAPICCommonInfo *info =
+        DO_UPCAST(IOAPICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+
+    if (info->pre_save) {
+        info->pre_save(s);
+    }
+}
+
+static int ioapic_dispatch_post_load(void *opaque, int version_id)
+{
+    IOAPICCommonState *s = opaque;
+    IOAPICCommonInfo *info =
+        DO_UPCAST(IOAPICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+
+    if (info->post_load) {
+        info->post_load(s);
+    }
+    return 0;
+}
+
+static int ioapic_init_common(SysBusDevice *dev)
+{
+    IOAPICCommonState *s = FROM_SYSBUS(IOAPICCommonState, dev);
+    IOAPICCommonInfo *info;
+    static int ioapic_no;
+
+    if (ioapic_no >= MAX_IOAPICS) {
+        return -1;
+    }
+
+    info = DO_UPCAST(IOAPICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+    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()
+    }
+};
+
+void ioapic_qdev_register(IOAPICCommonInfo *info)
+{
+    info->busdev.init = ioapic_init_common;
+    info->busdev.qdev.vmsd = &vmstate_ioapic_common;
+    info->busdev.qdev.no_user = 1;
+    sysbus_register_withprop(&info->busdev);
+}
diff --git a/hw/ioapic_internal.h b/hw/ioapic_internal.h
new file mode 100644
index 0000000..f8d90c0
--- /dev/null
+++ b/hw/ioapic_internal.h
@@ -0,0 +1,97 @@
+/*
+ *  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;
+
+struct IOAPICCommonState {
+    SysBusDevice busdev;
+    MemoryRegion io_memory;
+    uint8_t id;
+    uint8_t ioregsel;
+    uint32_t irr;
+    uint64_t ioredtbl[IOAPIC_NUM_PINS];
+};
+
+typedef struct IOAPICCommonInfo IOAPICCommonInfo;
+
+struct IOAPICCommonInfo {
+    SysBusDeviceInfo busdev;
+    void (*init)(IOAPICCommonState *s, int instance_no);
+    void (*pre_save)(IOAPICCommonState *s);
+    void (*post_load)(IOAPICCommonState *s);
+};
+
+void ioapic_qdev_register(IOAPICCommonInfo *info);
+void ioapic_reset_common(DeviceState *dev);
+
+#endif /* !QEMU_IOAPIC_INTERNAL_H */
commit ac791b881442e8f929ad0f7423f0e6f253dbef70
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Jan 10 12:24:10 2012 +0100

    ioapic: Drop post-load irr initialization
    
    As all devices undergo a reset prior to vmloa, and the reset value of
    irr is 0, we do not need to do this clearing for older vmstates
    explicitly. Dropping this redundant code will also make KVM integration
    a bit simpler.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/hw/ioapic.c b/hw/ioapic.c
index 27b07c6..0743af6 100644
--- a/hw/ioapic.c
+++ b/hw/ioapic.c
@@ -278,21 +278,9 @@ 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[]) {
commit 512709f559dce1690fa89fe2a67a8e1984cd3895
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sun Oct 16 14:38:45 2011 +0200

    i8259: Factor out base class for KVM reuse
    
    Analogously to the APIC, we will reuse some parts of the user space
    i8259 model for KVM. The base class provides a common device state, the
    vmstate, the property list, a reset core and some shared init bits.
    
    This also introduces a common helper to instantiate a single i8259 chip
    from the cascade-creating i8259_init function.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/Makefile.objs b/Makefile.objs
index 4f6d26c..6270a95 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -220,7 +220,7 @@ hw-obj-$(CONFIG_APPLESMC) += applesmc.o
 hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o ccid-card-passthru.o
 hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
 hw-obj-$(CONFIG_USB_REDIR) += usb-redir.o
-hw-obj-$(CONFIG_I8259) += i8259.o
+hw-obj-$(CONFIG_I8259) += i8259_common.o i8259.o
 
 # PPC devices
 hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o
diff --git a/hw/i8259.c b/hw/i8259.c
index cfaa35c..3005ce2 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,35 +41,6 @@
 //#define DEBUG_IRQ_LATENCY
 //#define DEBUG_IRQ_COUNT
 
-typedef struct PicState PicState;
-
-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
@@ -79,11 +51,11 @@ static uint64_t irq_count[16];
 static int64_t irq_time[16];
 #endif
 DeviceState *isa_pic;
-static PicState *slave_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;
 
@@ -98,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;
 
@@ -127,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;
 
@@ -144,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) || \
@@ -192,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) {
@@ -210,7 +182,7 @@ static void pic_intack(PicState *s, int irq)
 
 int pic_read_irq(DeviceState *d)
 {
-    PicState *s = DO_UPCAST(PicState, dev.qdev, d);
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
     int irq, irq2, intno;
 
     irq = pic_get_irq(s);
@@ -249,30 +221,15 @@ int pic_read_irq(DeviceState *d)
     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 = DO_UPCAST(PicState, dev.qdev, dev);
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, dev);
 
     pic_init_reset(s);
     s->elcr = 0;
@@ -281,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;
@@ -375,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) {
@@ -404,7 +361,7 @@ static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr,
 
 int pic_get_output(DeviceState *d)
 {
-    PicState *s = DO_UPCAST(PicState, dev.qdev, d);
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
 
     return (pic_get_irq(s) >= 0);
 }
@@ -412,43 +369,17 @@ int pic_get_output(DeviceState *d)
 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,
@@ -467,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 ? DO_UPCAST(PicState, dev.qdev, 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,
@@ -531,12 +451,7 @@ 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++) {
@@ -545,40 +460,27 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
 
     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 PICCommonInfo i8259_info = {
+    .isadev.qdev.name  = "isa-i8259",
+    .isadev.qdev.reset = pic_reset,
+    .init              = pic_init,
 };
 
 static void pic_register(void)
 {
-    isa_qdev_register(&i8259_info);
+    pic_qdev_register(&i8259_info);
 }
+
 device_init(pic_register)
diff --git a/hw/i8259_common.c b/hw/i8259_common.c
new file mode 100644
index 0000000..e515876
--- /dev/null
+++ b/hw/i8259_common.c
@@ -0,0 +1,147 @@
+/*
+ * 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;
+    PICCommonInfo *info =
+        DO_UPCAST(PICCommonInfo, isadev.qdev, s->dev.qdev.info);
+
+    if (info->pre_save) {
+        info->pre_save(s);
+    }
+}
+
+static int pic_dispatch_post_load(void *opaque, int version_id)
+{
+    PICCommonState *s = opaque;
+    PICCommonInfo *info =
+        DO_UPCAST(PICCommonInfo, isadev.qdev, s->dev.qdev.info);
+
+    if (info->post_load) {
+        info->post_load(s);
+    }
+    return 0;
+}
+
+static int pic_init_common(ISADevice *dev)
+{
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev, dev);
+    PICCommonInfo *info =
+        DO_UPCAST(PICCommonInfo, isadev.qdev, dev->qdev.info);
+
+    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(),
+};
+
+void pic_qdev_register(PICCommonInfo *info)
+{
+    info->isadev.init = pic_init_common;
+    info->isadev.qdev.size = sizeof(PICCommonState);
+    info->isadev.qdev.vmsd = &vmstate_pic_common;
+    info->isadev.qdev.no_user = 1;
+    info->isadev.qdev.props = pic_properties_common;
+    isa_qdev_register(&info->isadev);
+}
diff --git a/hw/i8259_internal.h b/hw/i8259_internal.h
new file mode 100644
index 0000000..13deb14
--- /dev/null
+++ b/hw/i8259_internal.h
@@ -0,0 +1,76 @@
+/*
+ * 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;
+
+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;
+};
+
+typedef struct PICCommonInfo PICCommonInfo;
+
+struct PICCommonInfo {
+    ISADeviceInfo isadev;
+    void (*init)(PICCommonState *s);
+    void (*pre_save)(PICCommonState *s);
+    void (*post_load)(PICCommonState *s);
+};
+
+void pic_reset_common(PICCommonState *s);
+
+ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master);
+
+void pic_qdev_register(PICCommonInfo *info);
+
+#endif /* !QEMU_I8259_INTERNAL_H */
commit 9aa78c425f6cd6a57ec53dd1a76233a080dc83b6
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Jan 10 16:31:16 2012 +0100

    i8259: Completely privatize PicState
    
    Use DeviceState instead of PicState in the public i8259 API. This is
    cleaner and allows to reorganize the PIC data structures for KVM reuse.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/hw/i8259.c b/hw/i8259.c
index 7331e0e..cfaa35c 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -40,6 +40,8 @@
 //#define DEBUG_IRQ_LATENCY
 //#define DEBUG_IRQ_COUNT
 
+typedef struct PicState PicState;
+
 struct PicState {
     ISADevice dev;
     uint8_t last_irr; /* edge detection */
@@ -76,7 +78,7 @@ static uint64_t irq_count[16];
 #ifdef DEBUG_IRQ_LATENCY
 static int64_t irq_time[16];
 #endif
-PicState *isa_pic;
+DeviceState *isa_pic;
 static PicState *slave_pic;
 
 /* return the highest priority found in mask (highest = smallest
@@ -206,8 +208,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)
 {
+    PicState *s = DO_UPCAST(PicState, dev.qdev, d);
     int irq, irq2, intno;
 
     irq = pic_get_irq(s);
@@ -269,7 +272,7 @@ static void pic_init_reset(PicState *s)
 
 static void pic_reset(DeviceState *dev)
 {
-    PicState *s = container_of(dev, PicState, dev.qdev);
+    PicState *s = DO_UPCAST(PicState, dev.qdev, dev);
 
     pic_init_reset(s);
     s->elcr = 0;
@@ -399,8 +402,10 @@ 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)
 {
+    PicState *s = DO_UPCAST(PicState, dev.qdev, d);
+
     return (pic_get_irq(s) >= 0);
 }
 
@@ -491,7 +496,7 @@ void pic_info(Monitor *mon)
         return;
     }
     for (i = 0; i < 2; i++) {
-        s = i == 0 ? isa_pic : slave_pic;
+        s = i == 0 ? DO_UPCAST(PicState, 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,
@@ -538,7 +543,7 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
         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);
diff --git a/hw/pc.h b/hw/pc.h
index 13e41f1..ece069a 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -62,11 +62,10 @@ 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);
+int pic_read_irq(DeviceState *d);
+int pic_get_output(DeviceState *d);
 void pic_info(Monitor *mon);
 void irq_info(Monitor *mon);
 
commit 7a380ca350f84b5b99391da20a2b4ea505b0524d
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sun Oct 16 12:19:12 2011 +0200

    apic: Open-code timer save/restore
    
    To enable migration between accelerated and non-accelerated APIC models,
    we will need to handle the timer saving and restoring specially and can
    no longer rely on the automatics of VMSTATE_TIMER. Specifically,
    accelerated model will not start any QEMUTimer.
    
    This patch therefore factors out the generic bits into apic_next_timer
    and use a post-load callback to implemented model-specific logic.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/hw/apic.c b/hw/apic.c
index 387a469..e59c964 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -521,25 +521,9 @@ static uint32_t apic_get_current_count(APICCommonState *s)
 
 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);
     }
 }
@@ -753,6 +737,15 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     }
 }
 
+static void apic_post_load(APICCommonState *s)
+{
+    if (s->timer_expiry != -1) {
+        qemu_mod_timer(s->timer, s->timer_expiry);
+    } else {
+        qemu_del_timer(s->timer);
+    }
+}
+
 static const MemoryRegionOps apic_io_ops = {
     .old_mmio = {
         .read = { apic_mem_readb, apic_mem_readw, apic_mem_readl, },
@@ -776,6 +769,7 @@ static APICCommonInfo apic_info = {
     .set_base = apic_set_base,
     .set_tpr = apic_set_tpr,
     .external_nmi = apic_external_nmi,
+    .post_load = apic_post_load,
 };
 
 static void apic_register_devices(void)
diff --git a/hw/apic_common.c b/hw/apic_common.c
index eef977f..e05369c 100644
--- a/hw/apic_common.c
+++ b/hw/apic_common.c
@@ -93,6 +93,39 @@ void apic_deliver_nmi(DeviceState *d)
     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);
@@ -120,7 +153,10 @@ void apic_init_reset(DeviceState *d)
     s->next_time = 0;
     s->wait_for_sipi = 1;
 
-    qemu_del_timer(s->timer);
+    if (s->timer) {
+        qemu_del_timer(s->timer);
+    }
+    s->timer_expiry = -1;
 }
 
 static void apic_reset_common(DeviceState *d)
@@ -203,12 +239,25 @@ static int apic_init_common(SysBusDevice *dev)
     return 0;
 }
 
+static int apic_dispatch_post_load(void *opaque, int version_id)
+{
+    APICCommonState *s = opaque;
+    APICCommonInfo *info =
+        DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+
+    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),
@@ -228,7 +277,8 @@ static const VMStateDescription vmstate_apic_common = {
         VMSTATE_UINT32(initial_count, APICCommonState),
         VMSTATE_INT64(initial_count_load_time, APICCommonState),
         VMSTATE_INT64(next_time, APICCommonState),
-        VMSTATE_TIMER(timer, APICCommonState),
+        VMSTATE_INT64(timer_expiry,
+                      APICCommonState), /* open-coded timer state */
         VMSTATE_END_OF_LIST()
     }
 };
diff --git a/hw/apic_internal.h b/hw/apic_internal.h
index a7433fb..1db4f06 100644
--- a/hw/apic_internal.h
+++ b/hw/apic_internal.h
@@ -92,6 +92,7 @@ struct APICCommonState {
     int64_t next_time;
     int idx;
     QEMUTimer *timer;
+    int64_t timer_expiry;
     int sipi_vector;
     int wait_for_sipi;
 };
@@ -104,9 +105,11 @@ struct APICCommonInfo {
     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);
 };
 
 void apic_report_irq_delivered(int delivered);
 void apic_qdev_register(APICCommonInfo *info);
+bool apic_next_timer(APICCommonState *s, int64_t current_time);
 
 #endif /* !QEMU_APIC_INTERNAL_H */
commit dae01685280cef9b70ade9167340b5373eada9e8
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sun Oct 16 11:16:36 2011 +0200

    apic: Factor out base class for KVM reuse
    
    The KVM in-kernel APIC model will reuse parts of the user space model
    while providing the same frontend view to guest and most management
    interfaces.
    
    Factor out an APIC base class to encapsulate those parts that will be
    shared by user space and KVM model. This class offers callback hooks for
    init, base/tpr setting, and the external NMI delivery that will be
    set via APICCommonInfo structure and implemented specifically in the
    subclasses.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/Makefile.target b/Makefile.target
index 0451b63..4446273 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -228,7 +228,7 @@ obj-y += device-hotplug.o
 # Hardware support
 obj-i386-y += vga.o
 obj-i386-y += mc146818rtc.o pc.o
-obj-i386-y += cirrus_vga.o sga.o apic.o ioapic.o piix_pci.o
+obj-i386-y += cirrus_vga.o sga.o apic_common.o apic.o ioapic.o piix_pci.o
 obj-i386-y += vmport.o
 obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
diff --git a/hw/apic.c b/hw/apic.c
index bec493b..387a469 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,10 +132,8 @@ void apic_deliver_pic_intr(DeviceState *d, int level)
     }
 }
 
-void apic_deliver_nmi(DeviceState *d)
+static void apic_external_nmi(APICCommonState *s)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
     apic_local_deliver(s, APIC_LVT_LINT1);
 }
 
@@ -234,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:
@@ -300,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 */
@@ -318,32 +237,12 @@ void cpu_set_apic_base(DeviceState *d, uint64_t val)
     }
 }
 
-uint64_t cpu_get_apic_base(DeviceState *d)
+static void apic_set_tpr(APICCommonState *s, uint8_t val)
 {
-    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)
-{
-    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)
 {
@@ -356,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;
 
@@ -372,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;
@@ -384,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);
@@ -400,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;
@@ -413,28 +312,7 @@ static void apic_update_irq(APICState *s)
     }
 }
 
-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;
-}
-
-static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
+static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
 {
     apic_report_irq_delivered(!get_bit(s->irr, vector_num));
 
@@ -446,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);
@@ -461,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)
@@ -481,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) {
@@ -515,36 +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;
-
-    qemu_del_timer(s->timer);
-}
-
-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);
@@ -552,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);
 
@@ -566,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:
@@ -612,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
@@ -637,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)
@@ -652,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;
@@ -670,7 +519,7 @@ 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;
 
@@ -697,7 +546,7 @@ static void apic_timer_update(APICState *s, int64_t current_time)
 
 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);
@@ -724,7 +573,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;
 
@@ -732,7 +581,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) {
@@ -815,7 +664,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,
@@ -831,7 +680,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);
 
@@ -904,96 +753,6 @@ 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)
-{
-    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;
-    }
-}
-
 static const MemoryRegionOps apic_io_ops = {
     .old_mmio = {
         .read = { apic_mem_readb, apic_mem_readw, apic_mem_readl, },
@@ -1002,41 +761,26 @@ 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 APICCommonInfo apic_info = {
+    .busdev.qdev.name = "apic",
+    .init = apic_init,
+    .set_base = apic_set_base,
+    .set_tpr = apic_set_tpr,
+    .external_nmi = apic_external_nmi,
 };
 
 static void apic_register_devices(void)
 {
-    sysbus_register_withprop(&apic_info);
+    apic_qdev_register(&apic_info);
 }
 
 device_init(apic_register_devices)
diff --git a/hw/apic.h b/hw/apic.h
index 8173d8a..a62d83b 100644
--- a/hw/apic.h
+++ b/hw/apic.h
@@ -10,7 +10,6 @@ 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_report_irq_delivered(int delivered);
 void apic_reset_irq_delivered(void);
 int apic_get_irq_delivered(void);
 void cpu_set_apic_base(DeviceState *s, uint64_t val);
diff --git a/hw/apic_common.c b/hw/apic_common.c
new file mode 100644
index 0000000..eef977f
--- /dev/null
+++ b/hw/apic_common.c
@@ -0,0 +1,252 @@
+/*
+ *  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)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    APICCommonInfo *info;
+
+    trace_cpu_set_apic_base(val);
+
+    if (s) {
+        info = DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+        info->set_base(s, val);
+    }
+}
+
+uint64_t cpu_get_apic_base(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, 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)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    APICCommonInfo *info;
+
+    if (s) {
+        info = DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+        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 = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    APICCommonInfo *info;
+
+    info = DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+    info->external_nmi(s);
+}
+
+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;
+
+    qemu_del_timer(s->timer);
+}
+
+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 = FROM_SYSBUS(APICCommonState, dev);
+    APICCommonInfo *info;
+    static int apic_no;
+
+    if (apic_no >= MAX_APICS) {
+        return -1;
+    }
+    s->idx = apic_no++;
+
+    info = DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+    info->init(s);
+
+    sysbus_init_mmio(&s->busdev, &s->io_memory);
+    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,
+    .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_TIMER(timer, APICCommonState),
+        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(),
+};
+
+
+void apic_qdev_register(APICCommonInfo *info)
+{
+    info->busdev.init = apic_init_common;
+    info->busdev.qdev.size = sizeof(APICCommonState),
+    info->busdev.qdev.vmsd = &vmstate_apic_common;
+    info->busdev.qdev.reset = apic_reset_common;
+    info->busdev.qdev.no_user = 1;
+    info->busdev.qdev.props = apic_properties_common;
+    sysbus_register_withprop(&info->busdev);
+}
diff --git a/hw/apic_internal.h b/hw/apic_internal.h
new file mode 100644
index 0000000..a7433fb
--- /dev/null
+++ b/hw/apic_internal.h
@@ -0,0 +1,112 @@
+/*
+ *  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;
+
+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;
+    int sipi_vector;
+    int wait_for_sipi;
+};
+
+typedef struct APICCommonInfo APICCommonInfo;
+
+struct APICCommonInfo {
+    SysBusDeviceInfo busdev;
+    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 apic_report_irq_delivered(int delivered);
+void apic_qdev_register(APICCommonInfo *info);
+
+#endif /* !QEMU_APIC_INTERNAL_H */
commit 343270ea8777fa95ce2c287fc00c2eaa53255265
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Dec 13 15:39:04 2011 +0100

    apic: Introduce apic_report_irq_delivered
    
    The in-kernel i8259 and IOAPIC backends for KVM will need this, so
    encapsulate the shared bits.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/hw/apic.c b/hw/apic.c
index b9d733c..bec493b 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -413,6 +413,13 @@ static void apic_update_irq(APICState *s)
     }
 }
 
+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);
@@ -429,9 +436,7 @@ int apic_get_irq_delivered(void)
 
 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)
diff --git a/hw/apic.h b/hw/apic.h
index a62d83b..8173d8a 100644
--- a/hw/apic.h
+++ b/hw/apic.h
@@ -10,6 +10,7 @@ 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_report_irq_delivered(int delivered);
 void apic_reset_irq_delivered(void);
 int apic_get_irq_delivered(void);
 void cpu_set_apic_base(DeviceState *s, uint64_t val);
diff --git a/trace-events b/trace-events
index c18435b..5a260d6 100644
--- a/trace-events
+++ b/trace-events
@@ -95,9 +95,9 @@ cpu_get_apic_base(uint64_t val) "%016"PRIx64
 apic_mem_readl(uint64_t addr, uint32_t val)  "%"PRIx64" = %08x"
 apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
 # coalescing
+apic_report_irq_delivered(int apic_irq_delivered) "coalescing %d"
 apic_reset_irq_delivered(int apic_irq_delivered) "old coalescing %d"
 apic_get_irq_delivered(int apic_irq_delivered) "returning coalescing %d"
-apic_set_irq(int apic_irq_delivered) "coalescing %d"
 
 # hw/cs4231.c
 cs4231_mem_readl_dreg(uint32_t reg, uint32_t ret) "read dreg %d: 0x%02x"
commit 02c091953cd8c24db46649ad2862b9648c50f865
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Oct 18 00:00:06 2011 +0800

    apic: Inject external NMI events via LINT1
    
    On real hardware, NMI button events are injected via the LINT1 line of
    the APICs. E.g. kdump expect this wiring and gets upset if the per-APIC
    LINT1 mask is not respected, i.e. if NMIs are injected to VCPUs that
    should not receive them. Change the APIC emulation code to reflect this.
    
    Based on qemu-kvm patch by Lai Jiangshan.
    
    CC: Lai Jiangshan <laijs at cn.fujitsu.com>
    Reported-by: Kenji Kaneshige <kaneshige.kenji at jp.fujitsu.com>
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/cpus.c b/cpus.c
index 2dae549..f45a438 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1217,7 +1217,11 @@ void qmp_inject_nmi(Error **errp)
     CPUState *env;
 
     for (env = first_cpu; env != NULL; env = env->next_cpu) {
-        cpu_interrupt(env, CPU_INTERRUPT_NMI);
+        if (!env->apic_state) {
+            cpu_interrupt(env, CPU_INTERRUPT_NMI);
+        } else {
+            apic_deliver_nmi(env->apic_state);
+        }
     }
 #else
     error_set(errp, QERR_UNSUPPORTED);
diff --git a/hw/apic.c b/hw/apic.c
index 4b97b17..b9d733c 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -205,6 +205,13 @@ void apic_deliver_pic_intr(DeviceState *d, int level)
     }
 }
 
+void apic_deliver_nmi(DeviceState *d)
+{
+    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+
+    apic_local_deliver(s, APIC_LVT_LINT1);
+}
+
 #define foreach_apic(apic, deliver_bitmask, code) \
 {\
     int __i, __j, __mask;\
diff --git a/hw/apic.h b/hw/apic.h
index a5c910f..a62d83b 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);
commit ab388a98148e5b44ba0b6bc0269fdb983b4a6838
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sun Oct 16 11:59:30 2011 +0200

    apic: Stop timer on reset
    
    All LVTs are masked on reset, so the timer becomes ineffective. Letting
    it tick nevertheless is harmless, but will at least create a spurious
    trace event.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/hw/apic.c b/hw/apic.c
index 9d0f460..4b97b17 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -528,6 +528,8 @@ void apic_init_reset(DeviceState *d)
     s->initial_count_load_time = 0;
     s->next_time = 0;
     s->wait_for_sipi = 1;
+
+    qemu_del_timer(s->timer);
 }
 
 static void apic_startup(APICState *s, int vector_num)
commit 3b9a6ee50e88c47f64486b6b143b1363fa5c327c
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Oct 15 10:01:27 2011 +0200

    kvm: Move kvmclock into hw/kvm folder
    
    More KVM-specific devices will come, so let's start with moving the
    kvmclock into a dedicated folder.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/Makefile.target b/Makefile.target
index 798dd30..0451b63 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -233,7 +233,7 @@ obj-i386-y += vmport.o
 obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
-obj-i386-$(CONFIG_KVM) += kvmclock.o
+obj-i386-$(CONFIG_KVM) += kvm/clock.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
@@ -424,7 +424,7 @@ qmp-commands-old.h: $(SRC_PATH)/qmp-commands.hx
 
 clean:
 	rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
-	rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o
+	rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o kvm/*.o
 	rm -f hmp-commands.h qmp-commands-old.h gdbstub-xml.c
 ifdef CONFIG_TRACE_SYSTEMTAP
 	rm -f *.stp
diff --git a/configure b/configure
index 467e87b..9d5175b 100755
--- a/configure
+++ b/configure
@@ -3363,6 +3363,7 @@ mkdir -p $target_dir/fpu
 mkdir -p $target_dir/tcg
 mkdir -p $target_dir/ide
 mkdir -p $target_dir/9pfs
+mkdir -p $target_dir/kvm
 if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" -o "$target" = "arm-bsd-user" -o "$target" = "armeb-bsd-user" ; then
   mkdir -p $target_dir/nwfpe
 fi
diff --git a/hw/kvm/clock.c b/hw/kvm/clock.c
new file mode 100644
index 0000000..bb28c08
--- /dev/null
+++ b/hw/kvm/clock.c
@@ -0,0 +1,120 @@
+/*
+ * QEMU KVM support, paravirtual clock device
+ *
+ * Copyright (C) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka        <jan.kiszka at siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "kvm.h"
+#include "hw/sysbus.h"
+#include "hw/kvm/clock.h"
+
+#include <linux/kvm.h>
+#include <linux/kvm_para.h>
+
+typedef struct KVMClockState {
+    SysBusDevice busdev;
+    uint64_t clock;
+    bool clock_valid;
+} KVMClockState;
+
+static void kvmclock_pre_save(void *opaque)
+{
+    KVMClockState *s = opaque;
+    struct kvm_clock_data data;
+    int ret;
+
+    if (s->clock_valid) {
+        return;
+    }
+    ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
+    if (ret < 0) {
+        fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
+        data.clock = 0;
+    }
+    s->clock = data.clock;
+    /*
+     * If the VM is stopped, declare the clock state valid to avoid re-reading
+     * it on next vmsave (which would return a different value). Will be reset
+     * when the VM is continued.
+     */
+    s->clock_valid = !runstate_is_running();
+}
+
+static int kvmclock_post_load(void *opaque, int version_id)
+{
+    KVMClockState *s = opaque;
+    struct kvm_clock_data data;
+
+    data.clock = s->clock;
+    data.flags = 0;
+    return kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
+}
+
+static void kvmclock_vm_state_change(void *opaque, int running,
+                                     RunState state)
+{
+    KVMClockState *s = opaque;
+
+    if (running) {
+        s->clock_valid = false;
+    }
+}
+
+static int kvmclock_init(SysBusDevice *dev)
+{
+    KVMClockState *s = FROM_SYSBUS(KVMClockState, dev);
+
+    qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
+    return 0;
+}
+
+static const VMStateDescription kvmclock_vmsd = {
+    .name = "kvmclock",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = kvmclock_pre_save,
+    .post_load = kvmclock_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(clock, KVMClockState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo kvmclock_info = {
+    .qdev.name = "kvmclock",
+    .qdev.size = sizeof(KVMClockState),
+    .qdev.vmsd = &kvmclock_vmsd,
+    .qdev.no_user = 1,
+    .init = kvmclock_init,
+};
+
+/* Note: Must be called after VCPU initialization. */
+void kvmclock_create(void)
+{
+    if (kvm_enabled() &&
+        first_cpu->cpuid_kvm_features & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
+                                         (1ULL << KVM_FEATURE_CLOCKSOURCE2))) {
+        sysbus_create_simple("kvmclock", -1, NULL);
+    }
+}
+
+static void kvmclock_register_device(void)
+{
+    if (kvm_enabled()) {
+        sysbus_register_withprop(&kvmclock_info);
+    }
+}
+
+device_init(kvmclock_register_device);
diff --git a/hw/kvm/clock.h b/hw/kvm/clock.h
new file mode 100644
index 0000000..252ea13
--- /dev/null
+++ b/hw/kvm/clock.h
@@ -0,0 +1,24 @@
+/*
+ * QEMU KVM support, paravirtual clock device
+ *
+ * Copyright (C) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka        <jan.kiszka at siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifdef CONFIG_KVM
+
+void kvmclock_create(void);
+
+#else /* CONFIG_KVM */
+
+static inline void kvmclock_create(void)
+{
+}
+
+#endif /* !CONFIG_KVM */
diff --git a/hw/kvmclock.c b/hw/kvmclock.c
deleted file mode 100644
index 3b9fb20..0000000
--- a/hw/kvmclock.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * QEMU KVM support, paravirtual clock device
- *
- * Copyright (C) 2011 Siemens AG
- *
- * Authors:
- *  Jan Kiszka        <jan.kiszka at siemens.com>
- *
- * This work is licensed under the terms of the GNU GPL version 2.
- * See the COPYING file in the top-level directory.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu-common.h"
-#include "sysemu.h"
-#include "sysbus.h"
-#include "kvm.h"
-#include "kvmclock.h"
-
-#include <linux/kvm.h>
-#include <linux/kvm_para.h>
-
-typedef struct KVMClockState {
-    SysBusDevice busdev;
-    uint64_t clock;
-    bool clock_valid;
-} KVMClockState;
-
-static void kvmclock_pre_save(void *opaque)
-{
-    KVMClockState *s = opaque;
-    struct kvm_clock_data data;
-    int ret;
-
-    if (s->clock_valid) {
-        return;
-    }
-    ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
-    if (ret < 0) {
-        fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
-        data.clock = 0;
-    }
-    s->clock = data.clock;
-    /*
-     * If the VM is stopped, declare the clock state valid to avoid re-reading
-     * it on next vmsave (which would return a different value). Will be reset
-     * when the VM is continued.
-     */
-    s->clock_valid = !runstate_is_running();
-}
-
-static int kvmclock_post_load(void *opaque, int version_id)
-{
-    KVMClockState *s = opaque;
-    struct kvm_clock_data data;
-
-    data.clock = s->clock;
-    data.flags = 0;
-    return kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
-}
-
-static void kvmclock_vm_state_change(void *opaque, int running,
-                                     RunState state)
-{
-    KVMClockState *s = opaque;
-
-    if (running) {
-        s->clock_valid = false;
-    }
-}
-
-static int kvmclock_init(SysBusDevice *dev)
-{
-    KVMClockState *s = FROM_SYSBUS(KVMClockState, dev);
-
-    qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
-    return 0;
-}
-
-static const VMStateDescription kvmclock_vmsd = {
-    .name = "kvmclock",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .pre_save = kvmclock_pre_save,
-    .post_load = kvmclock_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT64(clock, KVMClockState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static SysBusDeviceInfo kvmclock_info = {
-    .qdev.name = "kvmclock",
-    .qdev.size = sizeof(KVMClockState),
-    .qdev.vmsd = &kvmclock_vmsd,
-    .qdev.no_user = 1,
-    .init = kvmclock_init,
-};
-
-/* Note: Must be called after VCPU initialization. */
-void kvmclock_create(void)
-{
-    if (kvm_enabled() &&
-        first_cpu->cpuid_kvm_features & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
-                                         (1ULL << KVM_FEATURE_CLOCKSOURCE2))) {
-        sysbus_create_simple("kvmclock", -1, NULL);
-    }
-}
-
-static void kvmclock_register_device(void)
-{
-    if (kvm_enabled()) {
-        sysbus_register_withprop(&kvmclock_info);
-    }
-}
-
-device_init(kvmclock_register_device);
diff --git a/hw/kvmclock.h b/hw/kvmclock.h
deleted file mode 100644
index 252ea13..0000000
--- a/hw/kvmclock.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * QEMU KVM support, paravirtual clock device
- *
- * Copyright (C) 2011 Siemens AG
- *
- * Authors:
- *  Jan Kiszka        <jan.kiszka at siemens.com>
- *
- * This work is licensed under the terms of the GNU GPL version 2.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#ifdef CONFIG_KVM
-
-void kvmclock_create(void);
-
-#else /* CONFIG_KVM */
-
-static inline void kvmclock_create(void)
-{
-}
-
-#endif /* !CONFIG_KVM */
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 3aea3cc..cde810d 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"
commit 60ba3cc231d6bc7b802ad4fe6b6fc159ecb112e2
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Oct 15 14:33:17 2011 +0200

    msi: Generalize msix_supported to msi_supported
    
    Rename msix_supported to msi_supported and control MSI and MSI-X
    activation this way. That was likely to original intention for this
    flag, but MSI support came after MSI-X.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/hw/msi.c b/hw/msi.c
index f214fcf..5d6ceb6 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 5766018..3040bb0 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 f47d26b..3835eaa 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 7e04336..5aba22b 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/pc.c b/hw/pc.c
index 85304cf..04304e0 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -36,7 +36,7 @@
 #include "elf.h"
 #include "multiboot.h"
 #include "mc146818rtc.h"
-#include "msix.h"
+#include "msi.h"
 #include "sysbus.h"
 #include "sysemu.h"
 #include "blockdev.h"
@@ -896,7 +896,7 @@ static DeviceState *apic_init(void *env, uint8_t apic_id)
         apic_mapped = 1;
     }
 
-    msix_supported = 1;
+    msi_supported = true;
 
     return dev;
 }
commit eab70139a6772f1735444d4f1daadc7bcfa7dc47
Author: Vadim Rozenfeld <vrozenfe at redhat.com>
Date:   Sun Dec 18 22:48:14 2011 +0200

    hyper-v: initialize Hyper-V CPUID leaves.
    
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>

diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 04e65c5..1f56492 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -29,6 +29,7 @@
 #include "hw/pc.h"
 #include "hw/apic.h"
 #include "ioport.h"
+#include "hyperv.h"
 
 //#define DEBUG_KVM
 
@@ -373,11 +374,16 @@ int kvm_arch_init_vcpu(CPUState *env)
     cpuid_i = 0;
 
     /* Paravirtualization CPUIDs */
-    memcpy(signature, "KVMKVMKVM\0\0\0", 12);
     c = &cpuid_data.entries[cpuid_i++];
     memset(c, 0, sizeof(*c));
     c->function = KVM_CPUID_SIGNATURE;
-    c->eax = 0;
+    if (!hyperv_enabled()) {
+        memcpy(signature, "KVMKVMKVM\0\0\0", 12);
+        c->eax = 0;
+    } else {
+        memcpy(signature, "Microsoft Hv", 12);
+        c->eax = HYPERV_CPUID_MIN;
+    }
     c->ebx = signature[0];
     c->ecx = signature[1];
     c->edx = signature[2];
@@ -388,6 +394,54 @@ int kvm_arch_init_vcpu(CPUState *env)
     c->eax = env->cpuid_kvm_features &
         kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX);
 
+    if (hyperv_enabled()) {
+        memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12);
+        c->eax = signature[0];
+
+        c = &cpuid_data.entries[cpuid_i++];
+        memset(c, 0, sizeof(*c));
+        c->function = HYPERV_CPUID_VERSION;
+        c->eax = 0x00001bbc;
+        c->ebx = 0x00060001;
+
+        c = &cpuid_data.entries[cpuid_i++];
+        memset(c, 0, sizeof(*c));
+        c->function = HYPERV_CPUID_FEATURES;
+        if (hyperv_relaxed_timing_enabled()) {
+            c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
+        }
+        if (hyperv_vapic_recommended()) {
+            c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
+            c->eax |= HV_X64_MSR_APIC_ACCESS_AVAILABLE;
+        }
+
+        c = &cpuid_data.entries[cpuid_i++];
+        memset(c, 0, sizeof(*c));
+        c->function = HYPERV_CPUID_ENLIGHTMENT_INFO;
+        if (hyperv_relaxed_timing_enabled()) {
+            c->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED;
+        }
+        if (hyperv_vapic_recommended()) {
+            c->eax |= HV_X64_APIC_ACCESS_RECOMMENDED;
+        }
+        c->ebx = hyperv_get_spinlock_retries();
+
+        c = &cpuid_data.entries[cpuid_i++];
+        memset(c, 0, sizeof(*c));
+        c->function = HYPERV_CPUID_IMPLEMENT_LIMITS;
+        c->eax = 0x40;
+        c->ebx = 0x40;
+
+        c = &cpuid_data.entries[cpuid_i++];
+        memset(c, 0, sizeof(*c));
+        c->function = KVM_CPUID_SIGNATURE_NEXT;
+        memcpy(signature, "KVMKVMKVM\0\0\0", 12);
+        c->eax = 0;
+        c->ebx = signature[0];
+        c->ecx = signature[1];
+        c->edx = signature[2];
+    }
+
     has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
 
     cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused);
@@ -933,6 +987,13 @@ static int kvm_put_msrs(CPUState *env, int level)
             kvm_msr_entry_set(&msrs[n++], MSR_KVM_ASYNC_PF_EN,
                               env->async_pf_en_msr);
         }
+        if (hyperv_hypercall_available()) {
+            kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID, 0);
+            kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL, 0);
+        }
+        if (hyperv_vapic_recommended()) {
+            kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_APIC_ASSIST_PAGE, 0);
+        }
     }
     if (env->mcg_cap) {
         int i;
commit 28f52cc04d341045e810bd487a478fa9ec5f40be
Author: Vadim Rozenfeld <vrozenfe at redhat.com>
Date:   Sun Dec 18 22:48:13 2011 +0200

    hyper-v: introduce Hyper-V support infrastructure.
    
    [Jan: fix build with CONFIG_USER_ONLY]
    
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>

diff --git a/Makefile.target b/Makefile.target
index 06d79b8..798dd30 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -199,6 +199,8 @@ obj-$(CONFIG_NO_KVM) += kvm-stub.o
 obj-y += memory.o savevm.o
 LIBS+=-lz
 
+obj-i386-y +=hyperv.o
+
 QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
 QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index 91a104b..b9bfeaf 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -27,6 +27,8 @@
 #include "qemu-option.h"
 #include "qemu-config.h"
 
+#include "hyperv.h"
+
 /* feature flags taken from "Intel Processor Identification and the CPUID
  * Instruction" and AMD's "CPUID Specification".  In cases of disagreement
  * between feature naming conventions, aliases may be added.
@@ -716,6 +718,14 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
                     goto error;
                 }
                 x86_cpu_def->tsc_khz = tsc_freq / 1000;
+            } else if (!strcmp(featurestr, "hv_spinlocks")) {
+                char *err;
+                numvalue = strtoul(val, &err, 0);
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                hyperv_set_spinlock_retries(numvalue);
             } else {
                 fprintf(stderr, "unrecognized feature %s\n", featurestr);
                 goto error;
@@ -724,6 +734,10 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
             check_cpuid = 1;
         } else if (!strcmp(featurestr, "enforce")) {
             check_cpuid = enforce_cpuid = 1;
+        } else if (!strcmp(featurestr, "hv_relaxed")) {
+            hyperv_enable_relaxed_timing(true);
+        } else if (!strcmp(featurestr, "hv_vapic")) {
+            hyperv_enable_vapic_recommended(true);
         } else {
             fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
             goto error;
diff --git a/target-i386/hyperv.c b/target-i386/hyperv.c
new file mode 100644
index 0000000..f284e99
--- /dev/null
+++ b/target-i386/hyperv.c
@@ -0,0 +1,64 @@
+/*
+ * QEMU Hyper-V support
+ *
+ * Copyright Red Hat, Inc. 2011
+ *
+ * Author: Vadim Rozenfeld     <vrozenfe at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hyperv.h"
+
+static bool hyperv_vapic;
+static bool hyperv_relaxed_timing;
+static int hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY;
+
+void hyperv_enable_vapic_recommended(bool val)
+{
+    hyperv_vapic = val;
+}
+
+void hyperv_enable_relaxed_timing(bool val)
+{
+    hyperv_relaxed_timing = val;
+}
+
+void hyperv_set_spinlock_retries(int val)
+{
+    hyperv_spinlock_attempts = val;
+    if (hyperv_spinlock_attempts < 0xFFF) {
+        hyperv_spinlock_attempts = 0xFFF;
+    }
+}
+
+bool hyperv_enabled(void)
+{
+    return hyperv_hypercall_available() || hyperv_relaxed_timing_enabled();
+}
+
+bool hyperv_hypercall_available(void)
+{
+    if (hyperv_vapic ||
+        (hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_RETRY)) {
+      return true;
+    }
+    return false;
+}
+
+bool hyperv_vapic_recommended(void)
+{
+    return hyperv_vapic;
+}
+
+bool hyperv_relaxed_timing_enabled(void)
+{
+    return hyperv_relaxed_timing;
+}
+
+int hyperv_get_spinlock_retries(void)
+{
+    return hyperv_spinlock_attempts;
+}
diff --git a/target-i386/hyperv.h b/target-i386/hyperv.h
new file mode 100644
index 0000000..15467bf
--- /dev/null
+++ b/target-i386/hyperv.h
@@ -0,0 +1,43 @@
+/*
+ * QEMU Hyper-V support
+ *
+ * Copyright Red Hat, Inc. 2011
+ *
+ * Author: Vadim Rozenfeld     <vrozenfe at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_HW_HYPERV_H
+#define QEMU_HW_HYPERV_H 1
+
+#include "qemu-common.h"
+#include <asm/hyperv.h>
+
+#ifndef HYPERV_SPINLOCK_NEVER_RETRY
+#define HYPERV_SPINLOCK_NEVER_RETRY             0xFFFFFFFF
+#endif
+
+#ifndef KVM_CPUID_SIGNATURE_NEXT
+#define KVM_CPUID_SIGNATURE_NEXT                0x40000100
+#endif
+
+#ifndef CONFIG_USER_ONLY
+void hyperv_enable_vapic_recommended(bool val);
+void hyperv_enable_relaxed_timing(bool val);
+void hyperv_set_spinlock_retries(int val);
+#else
+static inline void hyperv_enable_vapic_recommended(bool val) { }
+static inline void hyperv_enable_relaxed_timing(bool val) { }
+static inline void hyperv_set_spinlock_retries(int val) { }
+#endif
+
+bool hyperv_enabled(void);
+bool hyperv_hypercall_available(void);
+bool hyperv_vapic_recommended(void);
+bool hyperv_relaxed_timing_enabled(void);
+int hyperv_get_spinlock_retries(void);
+
+#endif /* QEMU_HW_HYPERV_H */
commit dcfa486817c12ea41165265cfaaa236d11968626
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Tue Jan 17 13:17:38 2012 +0100

    Makefile: Remove generated headers on clean
    
    Running `make distclean' followed by a new out-of-tree build would fail
    due to stale generated QMP headers in the tree.
    
    Commit 611b727374ad76fb0078ea65bc1387194913980e (Makefile: remove more
    generated files on clean) made sure generated sources are removed.
    
    Also remove generated headers introduced in commit
    e3193601c84558c303b1773379da76fce80c0a56 (qapi: use middle mode in QMP
    server).
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Cc: Michael S. Tsirkin <mst at redhat.com>
    Cc: Paolo Bonzini <pbonzini at redhat.com>
    Cc: Luiz Capitulino <lcapitulino at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/Makefile b/Makefile
index d356f07..917fb9b 100644
--- a/Makefile
+++ b/Makefile
@@ -213,6 +213,7 @@ clean:
 	rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
 	rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
 	rm -f trace-dtrace.h trace-dtrace.h-timestamp
+	rm -f $(GENERATED_HEADERS)
 	rm -f $(GENERATED_SOURCES)
 	rm -rf $(qapi-dir)
 	$(MAKE) -C tests/tcg clean
commit e454e2e258e4a35ec164ec3bd5c168df56011513
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Tue Jan 17 13:16:05 2012 +0100

    Makefile: Exclude tests/Makefile in unconfigured tree
    
    Since commit dbfe06c62ccedc5b64e1c6466445133dd50f6de1 (build:
    split unit test builds to a separate makefile fragment),
    in absence of config-host.mak an undefined $(SRC_PATH) breaks
    `make distclean' due to /tests/Makefile not being include'able.
    
    Fix by only including when config-host.mak is present.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Cc: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/Makefile b/Makefile
index 2bbc547..d356f07 100644
--- a/Makefile
+++ b/Makefile
@@ -168,7 +168,9 @@ qemu-ga$(EXESUF): LIBS = $(LIBS_QGA)
 
 gen-out-type = $(subst .,-,$(suffix $@))
 
+ifneq ($(wildcard config-host.mak),)
 include $(SRC_PATH)/tests/Makefile
+endif
 
 $(qapi-dir)/qga-qapi-types.c $(qapi-dir)/qga-qapi-types.h :\
 $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py
commit 0f3c3cc9507872e8d06ae888b70eac055a6a39f8
Author: Andreas Färber <afaerber at suse.de>
Date:   Tue Jan 17 10:44:40 2012 +0100

    lm32: Fix mixup of uint32 and uint32_t
    
    Commit d23948b15a9920fb7f6374b55a6db1ecff81f3ee (lm32: add Milkymist
    VGAFB support) introduced a stray usage of the softfloat uint32 type.
    
    Use uint32_t instead.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Acked-by: Michael Walle <michael at walle.cc>
    Cc: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/milkymist-vgafb_template.h b/hw/milkymist-vgafb_template.h
index 69af9ef..1d33ee8 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;              \
commit 3c941c613a398ca62a9852f5bd29c1400ceffb3a
Author: Stefan Weil <sw at weilnetz.de>
Date:   Mon Jan 16 07:26:27 2012 +0100

    tests: Silence gtester in Makefile
    
    This prettifies make output a little by avoiding a very long line.
    As gtester prints the checks when they are run, no information is lost.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/tests/Makefile b/tests/Makefile
index efde63a..55e8eb0 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -36,4 +36,4 @@ test-qmp-commands: test-qmp-commands.o $(qobject-obj-y) $(qapi-obj-y) $(tools-ob
 
 .PHONY: check
 check: $(CHECKS)
-	gtester $(CHECKS)
+	$(call quiet-command, gtester $(CHECKS), "  CHECK")
commit 49cb826e8f66760d377cb2028b4274b9538d36e4
Author: Andreas Färber <afaerber at suse.de>
Date:   Mon Jan 16 01:46:52 2012 +0100

    qemu-tool: Fix mixup of int64 and int64_t
    
    Commit cbcfa0418f0c196afa765f5c9837b9344d1adcf3 (link the main loop and
    its dependencies into the tools) introduced stray usages of int64.
    
    Use int64_t instead.
    
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Cc: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/qemu-tool.c b/qemu-tool.c
index c73bf71..6b69668 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -59,12 +59,12 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
 {
 }
 
-int64 cpu_get_clock(void)
+int64_t cpu_get_clock(void)
 {
     abort();
 }
 
-int64 cpu_get_icount(void)
+int64_t cpu_get_icount(void)
 {
     abort();
 }
commit 2c30dd744aa02d31a8a3b87daaba0b2cb774f346
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Thu Jan 19 12:21:11 2012 +0530

    hw/9pfs: Add new security model mapped-file.
    
    This enable us to do passthrough equivalent security model on NFS directory.
    NFS server mostly do root squashing and don't support xattr. Hence we cannot
    use 'passthrough' or 'mapped' security model
    
    Also added "mapped-xattr" security to indicate earlier "mapped" security model
    Older name is still supported.
    
    POSIX rules regarding ctime update on chmod are not followed by this security model.
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 1e96c8b..956fda0 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -56,11 +56,15 @@ typedef struct extended_ops {
  * On failure ignore the error.
  */
 #define V9FS_SM_NONE                0x00000010
-#define V9FS_RDONLY                 0x00000020
-#define V9FS_PROXY_SOCK_FD          0x00000040
-#define V9FS_PROXY_SOCK_NAME        0x00000080
+/*
+ * uid/gid part of .virtfs_meatadata namespace
+ */
+#define V9FS_SM_MAPPED_FILE         0x00000020
+#define V9FS_RDONLY                 0x00000040
+#define V9FS_PROXY_SOCK_FD          0x00000080
+#define V9FS_PROXY_SOCK_NAME        0x00000100
 
-#define V9FS_SEC_MASK               0x0000001C
+#define V9FS_SEC_MASK               0x0000003C
 
 
 typedef struct FileOperations FileOperations;
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index b15838c..9345aae 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -76,6 +76,20 @@ int v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp, struct stat *stbuf)
                 err = -errno;
             }
         });
+    /*
+     * Some FS driver (local:mapped-file) can't support fetching attributes
+     * using file descriptor. Use Path name in that case.
+     */
+    if (err == -EOPNOTSUPP) {
+        err = v9fs_co_lstat(pdu, &fidp->path, stbuf);
+        if (err == -ENOENT) {
+            /*
+             * fstat on an unlinked file. Work with partial results
+             * returned from s->ops->fstat
+             */
+            err = 0;
+        }
+    }
     return err;
 }
 
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 642d5e2..41a1a82 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -91,15 +91,6 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
         s->ctx.fs_root = NULL;
     }
     s->ctx.exops.get_st_gen = NULL;
-
-    if (fse->export_flags & V9FS_SM_PASSTHROUGH) {
-        s->ctx.xops = passthrough_xattr_ops;
-    } else if (fse->export_flags & V9FS_SM_MAPPED) {
-        s->ctx.xops = mapped_xattr_ops;
-    } else if (fse->export_flags & V9FS_SM_NONE) {
-        s->ctx.xops = none_xattr_ops;
-    }
-
     len = strlen(conf->tag);
     if (len > MAX_TAG_LEN - 1) {
         fprintf(stderr, "mount tag '%s' (%d bytes) is longer than "
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index 3ae6ef2..6e3f9d1 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -20,6 +20,7 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 #include "qemu-xattr.h"
+#include <libgen.h>
 #include <linux/fs.h>
 #ifdef CONFIG_LINUX_MAGIC_H
 #include <linux/magic.h>
@@ -39,6 +40,54 @@
 #define BTRFS_SUPER_MAGIC 0x9123683E
 #endif
 
+#define VIRTFS_META_DIR ".virtfs_metadata"
+
+static const char *local_mapped_attr_path(FsContext *ctx,
+                                          const char *path, char *buffer)
+{
+    char *dir_name;
+    char *tmp_path = strdup(path);
+    char *base_name = basename(tmp_path);
+
+    /* NULL terminate the directory */
+    dir_name = tmp_path;
+    *(base_name - 1) = '\0';
+
+    snprintf(buffer, PATH_MAX, "%s/%s/%s/%s",
+             ctx->fs_root, dir_name, VIRTFS_META_DIR, base_name);
+    free(tmp_path);
+    return buffer;
+}
+
+#define ATTR_MAX 100
+static void local_mapped_file_attr(FsContext *ctx, const char *path,
+                                   struct stat *stbuf)
+{
+    FILE *fp;
+    char buf[ATTR_MAX];
+    char attr_path[PATH_MAX];
+
+    local_mapped_attr_path(ctx, path, attr_path);
+    fp = fopen(attr_path, "r");
+    if (!fp) {
+        return;
+    }
+    memset(buf, 0, ATTR_MAX);
+    while (fgets(buf, ATTR_MAX, fp)) {
+        if (!strncmp(buf, "virtfs.uid", 10)) {
+            stbuf->st_uid = atoi(buf+11);
+        } else if (!strncmp(buf, "virtfs.gid", 10)) {
+            stbuf->st_gid = atoi(buf+11);
+        } else if (!strncmp(buf, "virtfs.mode", 11)) {
+            stbuf->st_mode = atoi(buf+12);
+        } else if (!strncmp(buf, "virtfs.rdev", 11)) {
+            stbuf->st_rdev = atoi(buf+12);
+        }
+        memset(buf, 0, ATTR_MAX);
+    }
+    fclose(fp);
+}
+
 static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
 {
     int err;
@@ -71,10 +120,103 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
                         sizeof(dev_t)) > 0) {
                 stbuf->st_rdev = tmp_dev;
         }
+    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
+        local_mapped_file_attr(fs_ctx, path, stbuf);
+    }
+    return err;
+}
+
+static int local_create_mapped_attr_dir(FsContext *ctx, const char *path)
+{
+    int err;
+    char attr_dir[PATH_MAX];
+    char *tmp_path = strdup(path);
+
+    snprintf(attr_dir, PATH_MAX, "%s/%s/%s",
+             ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR);
+
+    err = mkdir(attr_dir, 0700);
+    if (err < 0 && errno == EEXIST) {
+        err = 0;
     }
+    free(tmp_path);
     return err;
 }
 
+static int local_set_mapped_file_attr(FsContext *ctx,
+                                      const char *path, FsCred *credp)
+{
+    FILE *fp;
+    int ret = 0;
+    char buf[ATTR_MAX];
+    char attr_path[PATH_MAX];
+    int uid = -1, gid = -1, mode = -1, rdev = -1;
+
+    fp = fopen(local_mapped_attr_path(ctx, path, attr_path), "r");
+    if (!fp) {
+        goto create_map_file;
+    }
+    memset(buf, 0, ATTR_MAX);
+    while (fgets(buf, ATTR_MAX, fp)) {
+        if (!strncmp(buf, "virtfs.uid", 10)) {
+            uid = atoi(buf+11);
+        } else if (!strncmp(buf, "virtfs.gid", 10)) {
+            gid = atoi(buf+11);
+        } else if (!strncmp(buf, "virtfs.mode", 11)) {
+            mode = atoi(buf+12);
+        } else if (!strncmp(buf, "virtfs.rdev", 11)) {
+            rdev = atoi(buf+12);
+        }
+        memset(buf, 0, ATTR_MAX);
+    }
+    fclose(fp);
+    goto update_map_file;
+
+create_map_file:
+    ret = local_create_mapped_attr_dir(ctx, path);
+    if (ret < 0) {
+        goto err_out;
+    }
+
+update_map_file:
+    fp = fopen(attr_path, "w");
+    if (!fp) {
+        ret = -1;
+        goto err_out;
+    }
+
+    if (credp->fc_uid != -1) {
+        uid = credp->fc_uid;
+    }
+    if (credp->fc_gid != -1) {
+        gid = credp->fc_gid;
+    }
+    if (credp->fc_mode != -1) {
+        mode = credp->fc_mode;
+    }
+    if (credp->fc_rdev != -1) {
+        rdev = credp->fc_rdev;
+    }
+
+
+    if (uid != -1) {
+        fprintf(fp, "virtfs.uid=%d\n", uid);
+    }
+    if (gid != -1) {
+        fprintf(fp, "virtfs.gid=%d\n", gid);
+    }
+    if (mode != -1) {
+        fprintf(fp, "virtfs.mode=%d\n", mode);
+    }
+    if (rdev != -1) {
+        fprintf(fp, "virtfs.rdev=%d\n", rdev);
+    }
+    fclose(fp);
+
+err_out:
+    return ret;
+}
+
 static int local_set_xattr(const char *path, FsCred *credp)
 {
     int err;
@@ -138,7 +280,8 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
     char buffer[PATH_MAX];
     char *path = fs_path->data;
 
-    if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
+    if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
+        (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
         int fd;
         fd = open(rpath(fs_ctx, path, buffer), O_RDONLY);
         if (fd == -1) {
@@ -203,7 +346,18 @@ static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
                            struct dirent *entry,
                            struct dirent **result)
 {
-    return readdir_r(fs->dir, entry, result);
+    int ret;
+
+again:
+    ret = readdir_r(fs->dir, entry, result);
+    if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
+        if (!ret && *result != NULL &&
+            !strcmp(entry->d_name, VIRTFS_META_DIR)) {
+            /* skp the meta data directory */
+            goto again;
+        }
+    }
+    return ret;
 }
 
 static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
@@ -264,6 +418,8 @@ static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
 
     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
         return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
+        return local_set_mapped_file_attr(fs_ctx, path, credp);
     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
                (fs_ctx->export_flags & V9FS_SM_NONE)) {
         return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode);
@@ -296,6 +452,18 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
             serrno = errno;
             goto err_end;
         }
+    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
+
+        err = mknod(rpath(fs_ctx, path, buffer),
+                    SM_LOCAL_MODE_BITS|S_IFREG, 0);
+        if (err == -1) {
+            goto out;
+        }
+        err = local_set_mapped_file_attr(fs_ctx, path, credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
                (fs_ctx->export_flags & V9FS_SM_NONE)) {
         err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
@@ -344,6 +512,17 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
             serrno = errno;
             goto err_end;
         }
+    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
+        err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
+        if (err == -1) {
+            goto out;
+        }
+        credp->fc_mode = credp->fc_mode|S_IFDIR;
+        err = local_set_mapped_file_attr(fs_ctx, path, credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
                (fs_ctx->export_flags & V9FS_SM_NONE)) {
         err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
@@ -404,6 +583,9 @@ static int local_fstat(FsContext *fs_ctx, int fid_type,
                       &tmp_dev, sizeof(dev_t)) > 0) {
                 stbuf->st_rdev = tmp_dev;
         }
+    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
+        errno = EOPNOTSUPP;
+        return -1;
     }
     return err;
 }
@@ -436,6 +618,19 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
             serrno = errno;
             goto err_end;
         }
+    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
+        fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
+        if (fd == -1) {
+            err = fd;
+            goto out;
+        }
+        credp->fc_mode = credp->fc_mode|S_IFREG;
+        /* Set client credentials in .virtfs_metadata directory files */
+        err = local_set_mapped_file_attr(fs_ctx, path, credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
                (fs_ctx->export_flags & V9FS_SM_NONE)) {
         fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
@@ -506,6 +701,35 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
             serrno = errno;
             goto err_end;
         }
+    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
+        int fd;
+        ssize_t oldpath_size, write_size;
+        fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR,
+                  SM_LOCAL_MODE_BITS);
+        if (fd == -1) {
+            err = fd;
+            goto out;
+        }
+        /* Write the oldpath (target) to the file. */
+        oldpath_size = strlen(oldpath);
+        do {
+            write_size = write(fd, (void *)oldpath, oldpath_size);
+        } while (write_size == -1 && errno == EINTR);
+
+        if (write_size != oldpath_size) {
+            serrno = errno;
+            close(fd);
+            err = -1;
+            goto err_end;
+        }
+        close(fd);
+        /* Set cleint credentials in symlink's xattr */
+        credp->fc_mode = credp->fc_mode|S_IFLNK;
+        err = local_set_mapped_file_attr(fs_ctx, newpath, credp);
+        if (err == -1) {
+            serrno = errno;
+            goto err_end;
+        }
     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
                (fs_ctx->export_flags & V9FS_SM_NONE)) {
         err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
@@ -548,6 +772,21 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
 
     ret = link(rpath(ctx, oldpath->data, buffer),
                rpath(ctx, newpath.data, buffer1));
+
+    /* now link the virtfs_metadata files */
+    if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
+        /* Link the .virtfs_metadata files. Create the metada directory */
+        ret = local_create_mapped_attr_dir(ctx, newpath.data);
+        if (ret < 0) {
+            goto err_out;
+        }
+        ret = link(local_mapped_attr_path(ctx, oldpath->data, buffer),
+                   local_mapped_attr_path(ctx, newpath.data, buffer1));
+        if (ret < 0 && errno != ENOENT) {
+            goto err_out;
+        }
+    }
+err_out:
     v9fs_string_free(&newpath);
     return ret;
 }
@@ -563,8 +802,21 @@ static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
 static int local_rename(FsContext *ctx, const char *oldpath,
                         const char *newpath)
 {
+    int err;
     char buffer[PATH_MAX], buffer1[PATH_MAX];
 
+    if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
+        err = local_create_mapped_attr_dir(ctx, newpath);
+        if (err < 0) {
+            return err;
+        }
+        /* rename the .virtfs_metadata files */
+        err = rename(local_mapped_attr_path(ctx, oldpath, buffer),
+                     local_mapped_attr_path(ctx, newpath, buffer1));
+        if (err < 0 && errno != ENOENT) {
+            return err;
+        }
+    }
     return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
 }
 
@@ -580,6 +832,8 @@ static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
                       credp->fc_uid, credp->fc_gid);
     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
         return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
+    } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
+        return local_set_mapped_file_attr(fs_ctx, path, credp);
     }
     return -1;
 }
@@ -595,8 +849,46 @@ static int local_utimensat(FsContext *s, V9fsPath *fs_path,
 
 static int local_remove(FsContext *ctx, const char *path)
 {
+    int err;
+    struct stat stbuf;
     char buffer[PATH_MAX];
+
+    if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
+        err =  lstat(rpath(ctx, path, buffer), &stbuf);
+        if (err) {
+            goto err_out;
+        }
+        /*
+         * If directory remove .virtfs_metadata contained in the
+         * directory
+         */
+        if (S_ISDIR(stbuf.st_mode)) {
+            sprintf(buffer, "%s/%s/%s", ctx->fs_root, path, VIRTFS_META_DIR);
+            err = remove(buffer);
+            if (err < 0 && errno != ENOENT) {
+                /*
+                 * We didn't had the .virtfs_metadata file. May be file created
+                 * in non-mapped mode ?. Ignore ENOENT.
+                 */
+                goto err_out;
+            }
+        }
+        /*
+         * Now remove the name from parent directory
+         * .virtfs_metadata directory
+         */
+        err = remove(local_mapped_attr_path(ctx, path, buffer));;
+        if (err < 0 && errno != ENOENT) {
+            /*
+             * We didn't had the .virtfs_metadata file. May be file created
+             * in non-mapped mode ?. Ignore ENOENT.
+             */
+            goto err_out;
+        }
+    }
     return remove(rpath(ctx, path, buffer));
+err_out:
+    return err;
 }
 
 static int local_fsync(FsContext *ctx, int fid_type,
@@ -696,12 +988,45 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
     int ret;
     V9fsString fullname;
     char buffer[PATH_MAX];
+
     v9fs_string_init(&fullname);
 
     v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
+    if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
+        if (flags == AT_REMOVEDIR) {
+            /*
+             * If directory remove .virtfs_metadata contained in the
+             * directory
+             */
+            sprintf(buffer, "%s/%s/%s", ctx->fs_root,
+                    fullname.data, VIRTFS_META_DIR);
+            ret = remove(buffer);
+            if (ret < 0 && errno != ENOENT) {
+                /*
+                 * We didn't had the .virtfs_metadata file. May be file created
+                 * in non-mapped mode ?. Ignore ENOENT.
+                 */
+                goto err_out;
+            }
+        }
+        /*
+         * Now remove the name from parent directory
+         * .virtfs_metadata directory.
+         */
+        ret = remove(local_mapped_attr_path(ctx, fullname.data, buffer));
+        if (ret < 0 && errno != ENOENT) {
+            /*
+             * We didn't had the .virtfs_metadata file. May be file created
+             * in non-mapped mode ?. Ignore ENOENT.
+             */
+            goto err_out;
+        }
+    }
+    /* Remove the name finally */
     ret = remove(rpath(ctx, fullname.data, buffer));
     v9fs_string_free(&fullname);
 
+err_out:
     return ret;
 }
 
@@ -736,6 +1061,19 @@ static int local_init(FsContext *ctx)
     int err = 0;
     struct statfs stbuf;
 
+    if (ctx->export_flags & V9FS_SM_PASSTHROUGH) {
+        ctx->xops = passthrough_xattr_ops;
+    } else if (ctx->export_flags & V9FS_SM_MAPPED) {
+        ctx->xops = mapped_xattr_ops;
+    } else if (ctx->export_flags & V9FS_SM_NONE) {
+        ctx->xops = none_xattr_ops;
+    } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
+        /*
+         * xattr operation for mapped-file and passthrough
+         * remain same.
+         */
+        ctx->xops = passthrough_xattr_ops;
+    }
     ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
 #ifdef FS_IOC_GETVERSION
     /*
@@ -770,13 +1108,17 @@ static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
 
     if (!strcmp(sec_model, "passthrough")) {
         fse->export_flags |= V9FS_SM_PASSTHROUGH;
-    } else if (!strcmp(sec_model, "mapped")) {
+    } else if (!strcmp(sec_model, "mapped") ||
+               !strcmp(sec_model, "mapped-xattr")) {
         fse->export_flags |= V9FS_SM_MAPPED;
     } else if (!strcmp(sec_model, "none")) {
         fse->export_flags |= V9FS_SM_NONE;
+    } else if (!strcmp(sec_model, "mapped-file")) {
+        fse->export_flags |= V9FS_SM_MAPPED_FILE;
     } else {
         fprintf(stderr, "Invalid security model %s specified, valid options are"
-                "\n\t [passthrough|mapped|none]\n", sec_model);
+                "\n\t [passthrough|mapped-xattr|mapped-file|none]\n",
+                sec_model);
         return -1;
     }
 
diff --git a/qemu-options.hx b/qemu-options.hx
index 6295cde..0cefd18 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -551,7 +551,7 @@ DEFHEADING()
 DEFHEADING(File system options:)
 
 DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
-    "-fsdev fsdriver,id=id[,path=path,][security_model={mapped|passthrough|none}]\n"
+    "-fsdev fsdriver,id=id[,path=path,][security_model={mapped-xattr|mapped-file|passthrough|none}]\n"
     " [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\n",
     QEMU_ARCH_ALL)
 
@@ -571,12 +571,13 @@ Specifies the export path for the file system device. Files under
 this path will be available to the 9p client on the guest.
 @item security_model=@var{security_model}
 Specifies the security model to be used for this export path.
-Supported security models are "passthrough", "mapped" and "none".
+Supported security models are "passthrough", "mapped-xattr", "mapped-file" and "none".
 In "passthrough" security model, files are stored using the same
 credentials as they are created on the guest. This requires qemu
-to run as root. In "mapped" security model, some of the file
+to run as root. In "mapped-xattr" security model, some of the file
 attributes like uid, gid, mode bits and link target are stored as
-file attributes. Directories exported by this security model cannot
+file attributes. For "mapped-file" these attributes are stored in the
+hidden .virtfs_metadata directory. Directories exported by this security model cannot
 interact with other unix tools. "none" security model is same as
 passthrough except the sever won't report failures if it fails to
 set file attributes like ownership. Security model is mandatory
@@ -616,7 +617,7 @@ DEFHEADING()
 DEFHEADING(Virtual File system pass-through options:)
 
 DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
-    "-virtfs local,path=path,mount_tag=tag,security_model=[mapped|passthrough|none]\n"
+    "-virtfs local,path=path,mount_tag=tag,security_model=[mapped-xattr|mapped-file|passthrough|none]\n"
     "        [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\n",
     QEMU_ARCH_ALL)
 
@@ -637,12 +638,13 @@ Specifies the export path for the file system device. Files under
 this path will be available to the 9p client on the guest.
 @item security_model=@var{security_model}
 Specifies the security model to be used for this export path.
-Supported security models are "passthrough", "mapped" and "none".
+Supported security models are "passthrough", "mapped-xattr", "mapped-file" and "none".
 In "passthrough" security model, files are stored using the same
 credentials as they are created on the guest. This requires qemu
-to run as root. In "mapped" security model, some of the file
+to run as root. In "mapped-xattr" security model, some of the file
 attributes like uid, gid, mode bits and link target are stored as
-file attributes. Directories exported by this security model cannot
+file attributes. For "mapped-file" these attributes are stored in the
+hidden .virtfs_metadata directory. Directories exported by this security model cannot
 interact with other unix tools. "none" security model is same as
 passthrough except the sever won't report failures if it fails to
 set file attributes like ownership. Security model is mandatory only
commit 939a1cc399adb92640d156097d528b6471c136ae
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Wed Jan 4 22:23:34 2012 +0000

    block: use proper qerrors in qmp_block_resize
    
    Let's report specific errors so that management tools and users can
    identify the problem.
    
    Two new qerrors are needed:
     * QERR_DEVICE_HAS_NO_MEDIUM for ENOMEDIUM
     * QERR_DEVICE_IS_READ_ONLY for EACCES
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/blockdev.c b/blockdev.c
index 5d16137..1f83c88 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -848,11 +848,6 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
     return 0;
 }
 
-/*
- * XXX: replace the QERR_UNDEFINED_ERROR errors with real values once the
- * existing QERR_ macro mess is cleaned up.  A good example for better
- * error reports can be found in the qemu-img resize code.
- */
 void qmp_block_resize(const char *device, int64_t size, Error **errp)
 {
     BlockDriverState *bs;
@@ -864,12 +859,27 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp)
     }
 
     if (size < 0) {
-        error_set(errp, QERR_UNDEFINED_ERROR);
+        error_set(errp, QERR_INVALID_PARAMETER_VALUE, "size", "a >0 size");
         return;
     }
 
-    if (bdrv_truncate(bs, size)) {
+    switch (bdrv_truncate(bs, size)) {
+    case 0:
+        break;
+    case -ENOMEDIUM:
+        error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
+        break;
+    case -ENOTSUP:
+        error_set(errp, QERR_UNSUPPORTED);
+        break;
+    case -EACCES:
+        error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
+        break;
+    case -EBUSY:
+        error_set(errp, QERR_DEVICE_IN_USE, device);
+        break;
+    default:
         error_set(errp, QERR_UNDEFINED_ERROR);
-        return;
+        break;
     }
 }
diff --git a/qapi-schema.json b/qapi-schema.json
index 9b154cc..735eb35 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1064,8 +1064,11 @@
 #
 # Returns: nothing on success
 #          If @device is not a valid block device, DeviceNotFound
-#
-# Notes: This command returns UndefinedError in a number of error conditions.
+#          If @size is negative, InvalidParameterValue
+#          If the block device has no medium inserted, DeviceHasNoMedium
+#          If the block device does not support resize, Unsupported
+#          If the block device is read-only, DeviceIsReadOnly
+#          If a long-running operation is using the device, DeviceInUse
 #
 # Since: 0.14.0
 ##
diff --git a/qerror.c b/qerror.c
index 2979b3e..3d95383 100644
--- a/qerror.c
+++ b/qerror.c
@@ -80,6 +80,10 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "Migration is disabled when using feature '%(feature)' in device '%(device)'",
     },
     {
+        .error_fmt = QERR_DEVICE_HAS_NO_MEDIUM,
+        .desc      = "Device '%(device)' has no medium",
+    },
+    {
         .error_fmt = QERR_DEVICE_INIT_FAILED,
         .desc      = "Device '%(device)' could not be initialized",
     },
@@ -88,6 +92,10 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "Device '%(device)' is in use",
     },
     {
+        .error_fmt = QERR_DEVICE_IS_READ_ONLY,
+        .desc      = "Device '%(device)' is read only",
+    },
+    {
         .error_fmt = QERR_DEVICE_LOCKED,
         .desc      = "Device '%(device)' is locked",
     },
diff --git a/qerror.h b/qerror.h
index be4e865..89160dd 100644
--- a/qerror.h
+++ b/qerror.h
@@ -81,12 +81,18 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
     "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
 
+#define QERR_DEVICE_HAS_NO_MEDIUM \
+    "{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }"
+
 #define QERR_DEVICE_INIT_FAILED \
     "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_IN_USE \
     "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
 
+#define QERR_DEVICE_IS_READ_ONLY \
+    "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }"
+
 #define QERR_DEVICE_LOCKED \
     "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
 
commit c1303596a196613f1a765f8a536319577b2bb844
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Wed Jan 4 17:38:22 2012 +0000

    qerror: restore alphabetical order over qerrors
    
    Over time these must have gotten out of order.  Put everything back in
    alphabetical order.
    
    This is purely a clean up.  In practice nothing depends on the order.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/qerror.c b/qerror.c
index 62c0c70..2979b3e 100644
--- a/qerror.c
+++ b/qerror.c
@@ -44,6 +44,10 @@ static const QType qerror_type = {
  */
 static const QErrorStringTable qerror_table[] = {
     {
+        .error_fmt = QERR_ADD_CLIENT_FAILED,
+        .desc      = "Could not add client",
+    },
+    {
         .error_fmt = QERR_BAD_BUS_FOR_DEVICE,
         .desc      = "Device '%(device)' can't go on a %(bad_bus_type) bus",
     },
@@ -52,26 +56,30 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'",
     },
     {
-        .error_fmt = QERR_BUS_NOT_FOUND,
-        .desc      = "Bus '%(bus)' not found",
-    },
-    {
         .error_fmt = QERR_BUS_NO_HOTPLUG,
         .desc      = "Bus '%(bus)' does not support hotplugging",
     },
     {
-        .error_fmt = QERR_COMMAND_NOT_FOUND,
-        .desc      = "The command %(name) has not been found",
+        .error_fmt = QERR_BUS_NOT_FOUND,
+        .desc      = "Bus '%(bus)' not found",
     },
     {
         .error_fmt = QERR_COMMAND_DISABLED,
         .desc      = "The command %(name) has been disabled for this instance",
     },
     {
+        .error_fmt = QERR_COMMAND_NOT_FOUND,
+        .desc      = "The command %(name) has not been found",
+    },
+    {
         .error_fmt = QERR_DEVICE_ENCRYPTED,
         .desc      = "Device '%(device)' is encrypted",
     },
     {
+        .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
+        .desc      = "Migration is disabled when using feature '%(feature)' in device '%(device)'",
+    },
+    {
         .error_fmt = QERR_DEVICE_INIT_FAILED,
         .desc      = "Device '%(device)' could not be initialized",
     },
@@ -80,10 +88,6 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "Device '%(device)' is in use",
     },
     {
-        .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
-        .desc      = "Migration is disabled when using feature '%(feature)' in device '%(device)'",
-    },
-    {
         .error_fmt = QERR_DEVICE_LOCKED,
         .desc      = "Device '%(device)' is locked",
     },
@@ -92,6 +96,14 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "Device '%(device)' has multiple child busses",
     },
     {
+        .error_fmt = QERR_DEVICE_NO_BUS,
+        .desc      = "Device '%(device)' has no child bus",
+    },
+    {
+        .error_fmt = QERR_DEVICE_NO_HOTPLUG,
+        .desc      = "Device '%(device)' does not support hotplugging",
+    },
+    {
         .error_fmt = QERR_DEVICE_NOT_ACTIVE,
         .desc      = "Device '%(device)' has not been activated",
     },
@@ -108,14 +120,6 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "Device '%(device)' is not removable",
     },
     {
-        .error_fmt = QERR_DEVICE_NO_BUS,
-        .desc      = "Device '%(device)' has no child bus",
-    },
-    {
-        .error_fmt = QERR_DEVICE_NO_HOTPLUG,
-        .desc      = "Device '%(device)' does not support hotplugging",
-    },
-    {
         .error_fmt = QERR_DUPLICATE_ID,
         .desc      = "Duplicate ID '%(id)' for %(object)",
     },
@@ -140,6 +144,10 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "Invalid parameter '%(name)'",
     },
     {
+        .error_fmt = QERR_INVALID_PARAMETER_COMBINATION,
+        .desc      = "Invalid parameter combination",
+    },
+    {
         .error_fmt = QERR_INVALID_PARAMETER_TYPE,
         .desc      = "Invalid parameter type, expected: %(expected)",
     },
@@ -156,15 +164,15 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "An IO error has occurred",
     },
     {
-        .error_fmt = QERR_JSON_PARSING,
-        .desc      = "Invalid JSON syntax",
-    },
-    {
         .error_fmt = QERR_JSON_PARSE_ERROR,
         .desc      = "JSON parse error, %(message)",
 
     },
     {
+        .error_fmt = QERR_JSON_PARSING,
+        .desc      = "Invalid JSON syntax",
+    },
+    {
         .error_fmt = QERR_KVM_MISSING_CAP,
         .desc      = "Using KVM without %(capability), %(feature) unavailable",
     },
@@ -210,6 +218,14 @@ static const QErrorStringTable qerror_table[] = {
                      "value %(value) (minimum: %(min), maximum: %(max)'",
     },
     {
+        .error_fmt = QERR_QGA_COMMAND_FAILED,
+        .desc      = "Guest agent command failed, error was '%(message)'",
+    },
+    {
+        .error_fmt = QERR_QGA_LOGGING_FAILED,
+        .desc      = "Guest agent failed to log non-optional log statement",
+    },
+    {
         .error_fmt = QERR_QMP_BAD_INPUT_OBJECT,
         .desc      = "Expected '%(expected)' in QMP input",
     },
@@ -230,10 +246,6 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "Could not set password",
     },
     {
-        .error_fmt = QERR_ADD_CLIENT_FAILED,
-        .desc      = "Could not add client",
-    },
-    {
         .error_fmt = QERR_TOO_MANY_FILES,
         .desc      = "Too many open files",
     },
@@ -242,15 +254,15 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "An undefined error has occurred",
     },
     {
-        .error_fmt = QERR_UNSUPPORTED,
-        .desc      = "this feature or command is not currently supported",
-    },
-    {
         .error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
         .desc      = "'%(device)' uses a %(format) feature which is not "
                      "supported by this qemu version: %(feature)",
     },
     {
+        .error_fmt = QERR_UNSUPPORTED,
+        .desc      = "this feature or command is not currently supported",
+    },
+    {
         .error_fmt = QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
         .desc      = "Migration is disabled when VirtFS export path '%(path)' "
                      "is mounted in the guest using mount_tag '%(tag)'",
@@ -259,18 +271,6 @@ static const QErrorStringTable qerror_table[] = {
         .error_fmt = QERR_VNC_SERVER_FAILED,
         .desc      = "Could not start VNC server on %(target)",
     },
-    {
-        .error_fmt = QERR_QGA_LOGGING_FAILED,
-        .desc      = "Guest agent failed to log non-optional log statement",
-    },
-    {
-        .error_fmt = QERR_QGA_COMMAND_FAILED,
-        .desc      = "Guest agent command failed, error was '%(message)'",
-    },
-    {
-        .error_fmt = QERR_INVALID_PARAMETER_COMBINATION,
-        .desc      = "Invalid parameter combination",
-    },
     {}
 };
 
diff --git a/qerror.h b/qerror.h
index 40e52e8..be4e865 100644
--- a/qerror.h
+++ b/qerror.h
@@ -51,42 +51,54 @@ QError *qobject_to_qerror(const QObject *obj);
  * Please keep the definitions in alphabetical order.
  * Use scripts/check-qerror.sh to check.
  */
+#define QERR_ADD_CLIENT_FAILED \
+    "{ 'class': 'AddClientFailed', 'data': {} }"
+
 #define QERR_BAD_BUS_FOR_DEVICE \
     "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
 
 #define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
     "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
 
-#define QERR_BUS_NOT_FOUND \
-    "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
+#define QERR_BUFFER_OVERRUN \
+    "{ 'class': 'BufferOverrun', 'data': {} }"
 
 #define QERR_BUS_NO_HOTPLUG \
     "{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }"
 
-#define QERR_COMMAND_NOT_FOUND \
-    "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
+#define QERR_BUS_NOT_FOUND \
+    "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
 
 #define QERR_COMMAND_DISABLED \
     "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }"
 
+#define QERR_COMMAND_NOT_FOUND \
+    "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
+
 #define QERR_DEVICE_ENCRYPTED \
     "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }"
 
+#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
+    "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
+
 #define QERR_DEVICE_INIT_FAILED \
     "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_IN_USE \
     "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
 
-#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
-    "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
-
 #define QERR_DEVICE_LOCKED \
     "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
 
 #define QERR_DEVICE_MULTIPLE_BUSSES \
     "{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }"
 
+#define QERR_DEVICE_NO_BUS \
+    "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
+
+#define QERR_DEVICE_NO_HOTPLUG \
+    "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
+
 #define QERR_DEVICE_NOT_ACTIVE \
     "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }"
 
@@ -99,12 +111,6 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_DEVICE_NOT_REMOVABLE \
     "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }"
 
-#define QERR_DEVICE_NO_BUS \
-    "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
-
-#define QERR_DEVICE_NO_HOTPLUG \
-    "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
-
 #define QERR_DUPLICATE_ID \
     "{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }"
 
@@ -114,12 +120,18 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_FD_NOT_SUPPLIED \
     "{ 'class': 'FdNotSupplied', 'data': {} }"
 
+#define QERR_FEATURE_DISABLED \
+    "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
+
 #define QERR_INVALID_BLOCK_FORMAT \
     "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }"
 
 #define QERR_INVALID_PARAMETER \
     "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }"
 
+#define QERR_INVALID_PARAMETER_COMBINATION \
+    "{ 'class': 'InvalidParameterCombination', 'data': {} }"
+
 #define QERR_INVALID_PARAMETER_TYPE \
     "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }"
 
@@ -132,14 +144,11 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_IO_ERROR \
     "{ 'class': 'IOError', 'data': {} }"
 
-#define QERR_JSON_PARSING \
-    "{ 'class': 'JSONParsing', 'data': {} }"
-
 #define QERR_JSON_PARSE_ERROR \
     "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
 
-#define QERR_BUFFER_OVERRUN \
-    "{ 'class': 'BufferOverrun', 'data': {} }"
+#define QERR_JSON_PARSING \
+    "{ 'class': 'JSONParsing', 'data': {} }"
 
 #define QERR_KVM_MISSING_CAP \
     "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
@@ -174,6 +183,12 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_PROPERTY_VALUE_OUT_OF_RANGE \
     "{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }"
 
+#define QERR_QGA_COMMAND_FAILED \
+    "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
+
+#define QERR_QGA_LOGGING_FAILED \
+    "{ 'class': 'QgaLoggingFailed', 'data': {} }"
+
 #define QERR_QMP_BAD_INPUT_OBJECT \
     "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }"
 
@@ -189,37 +204,22 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_SET_PASSWD_FAILED \
     "{ 'class': 'SetPasswdFailed', 'data': {} }"
 
-#define QERR_ADD_CLIENT_FAILED \
-    "{ 'class': 'AddClientFailed', 'data': {} }"
-
 #define QERR_TOO_MANY_FILES \
     "{ 'class': 'TooManyFiles', 'data': {} }"
 
 #define QERR_UNDEFINED_ERROR \
     "{ 'class': 'UndefinedError', 'data': {} }"
 
-#define QERR_UNSUPPORTED \
-    "{ 'class': 'Unsupported', 'data': {} }"
-
 #define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
     "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
 
+#define QERR_UNSUPPORTED \
+    "{ 'class': 'Unsupported', 'data': {} }"
+
 #define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \
     "{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }"
 
 #define QERR_VNC_SERVER_FAILED \
     "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
 
-#define QERR_FEATURE_DISABLED \
-    "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
-
-#define QERR_QGA_LOGGING_FAILED \
-    "{ 'class': 'QgaLoggingFailed', 'data': {} }"
-
-#define QERR_QGA_COMMAND_FAILED \
-    "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
-
-#define QERR_INVALID_PARAMETER_COMBINATION \
-    "{ 'class': 'InvalidParameterCombination', 'data': {} }"
-
 #endif /* QERROR_H */
commit 9737383beb515a583fdb6f2aafa631fcd6797068
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Wed Jan 4 22:23:32 2012 +0000

    qerror: add check-qerror.sh to verify alphabetical order
    
    We're supposed to keep qerror definitions and table entries in
    alphabetical order.  In practice this is not checked.
    
    I haven't found a nice way to integrate this into the makefile yet but
    we can at least have this script which verifies that qerrors are in
    alphabetical order.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/qerror.c b/qerror.c
index 9a75d06..62c0c70 100644
--- a/qerror.c
+++ b/qerror.c
@@ -40,8 +40,7 @@ static const QType qerror_type = {
  * "running out of foo: %(foo)%%"
  *
  * Please keep the entries in alphabetical order.
- * Use "sed -n '/^static.*qerror_table\[\]/,/^};/s/QERR_/&/gp' qerror.c | sort -c"
- * to check.
+ * Use scripts/check-qerror.sh to check.
  */
 static const QErrorStringTable qerror_table[] = {
     {
diff --git a/qerror.h b/qerror.h
index 27800fe..40e52e8 100644
--- a/qerror.h
+++ b/qerror.h
@@ -49,7 +49,7 @@ QError *qobject_to_qerror(const QObject *obj);
 /*
  * QError class list
  * Please keep the definitions in alphabetical order.
- * Use "grep '^#define QERR_' qerror.h | sort -c" to check.
+ * Use scripts/check-qerror.sh to check.
  */
 #define QERR_BAD_BUS_FOR_DEVICE \
     "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
diff --git a/scripts/check-qerror.sh b/scripts/check-qerror.sh
new file mode 100755
index 0000000..af7fbd5
--- /dev/null
+++ b/scripts/check-qerror.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+# This script verifies that qerror definitions and table entries are
+# alphabetically ordered.
+
+check_order() {
+  errmsg=$1
+  shift
+
+  # sort -C verifies order but does not print a message.  sort -c does print a
+  # message.  These options are both in POSIX.
+  if ! "$@" | sort -C; then
+    echo "$errmsg"
+    "$@" | sort -c
+    exit 1
+  fi
+  return 0
+}
+
+check_order 'Definitions in qerror.h must be in alphabetical order:' \
+            grep '^#define QERR_' qerror.h
+check_order 'Entries in qerror.c:qerror_table must be in alphabetical order:' \
+            sed -n '/^static.*qerror_table\[\]/,/^};/s/QERR_/&/gp' qerror.c
commit aba2107a2649f3eeab4422efa17dbd06929abccd
Author: Stefan Weil <sw at weilnetz.de>
Date:   Fri Dec 23 20:34:38 2011 +0100

    qmp: Add missing gcc format attribute and fix format string
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/test-qmp-input-visitor.c b/test-qmp-input-visitor.c
index 1f3ab03..926db5c 100644
--- a/test-qmp-input-visitor.c
+++ b/test-qmp-input-visitor.c
@@ -38,8 +38,9 @@ static void visitor_input_teardown(TestInputVisitorData *data,
 /* This is provided instead of a test setup function so that the JSON
    string used by the tests are kept in the test functions (and not
    int main()) */
-static Visitor *visitor_input_test_init(TestInputVisitorData *data,
-                                        const char *json_string, ...)
+static GCC_FMT_ATTR(2, 3)
+Visitor *visitor_input_test_init(TestInputVisitorData *data,
+                                 const char *json_string, ...)
 {
     Visitor *v;
     va_list ap;
@@ -66,7 +67,7 @@ static void test_visitor_in_int(TestInputVisitorData *data,
     Error *errp = NULL;
     Visitor *v;
 
-    v = visitor_input_test_init(data, "%d", value);
+    v = visitor_input_test_init(data, "%" PRId64, value);
 
     visit_type_int(v, &res, NULL, &errp);
     g_assert(!error_is_set(&errp));
commit 80047da59b17053b69e8bdc143c8fb4b3a44cb7d
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Wed Dec 14 16:49:14 2011 -0200

    qapi: Convert block_set_io_throttle
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/blockdev.c b/blockdev.c
index 8df78ce..5d16137 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -775,46 +775,29 @@ void qmp_change_blockdev(const char *device, const char *filename,
 }
 
 /* throttling disk I/O limits */
-int do_block_set_io_throttle(Monitor *mon,
-                       const QDict *qdict, QObject **ret_data)
+void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
+                               int64_t bps_wr, int64_t iops, int64_t iops_rd,
+                               int64_t iops_wr, Error **errp)
 {
     BlockIOLimit io_limits;
-    const char *devname = qdict_get_str(qdict, "device");
     BlockDriverState *bs;
 
-    io_limits.bps[BLOCK_IO_LIMIT_TOTAL]
-                        = qdict_get_try_int(qdict, "bps", -1);
-    io_limits.bps[BLOCK_IO_LIMIT_READ]
-                        = qdict_get_try_int(qdict, "bps_rd", -1);
-    io_limits.bps[BLOCK_IO_LIMIT_WRITE]
-                        = qdict_get_try_int(qdict, "bps_wr", -1);
-    io_limits.iops[BLOCK_IO_LIMIT_TOTAL]
-                        = qdict_get_try_int(qdict, "iops", -1);
-    io_limits.iops[BLOCK_IO_LIMIT_READ]
-                        = qdict_get_try_int(qdict, "iops_rd", -1);
-    io_limits.iops[BLOCK_IO_LIMIT_WRITE]
-                        = qdict_get_try_int(qdict, "iops_wr", -1);
-
-    bs = bdrv_find(devname);
+    bs = bdrv_find(device);
     if (!bs) {
-        qerror_report(QERR_DEVICE_NOT_FOUND, devname);
-        return -1;
+        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+        return;
     }
 
-    if ((io_limits.bps[BLOCK_IO_LIMIT_TOTAL] == -1)
-        || (io_limits.bps[BLOCK_IO_LIMIT_READ] == -1)
-        || (io_limits.bps[BLOCK_IO_LIMIT_WRITE] == -1)
-        || (io_limits.iops[BLOCK_IO_LIMIT_TOTAL] == -1)
-        || (io_limits.iops[BLOCK_IO_LIMIT_READ] == -1)
-        || (io_limits.iops[BLOCK_IO_LIMIT_WRITE] == -1)) {
-        qerror_report(QERR_MISSING_PARAMETER,
-                      "bps/bps_rd/bps_wr/iops/iops_rd/iops_wr");
-        return -1;
-    }
+    io_limits.bps[BLOCK_IO_LIMIT_TOTAL] = bps;
+    io_limits.bps[BLOCK_IO_LIMIT_READ]  = bps_rd;
+    io_limits.bps[BLOCK_IO_LIMIT_WRITE] = bps_wr;
+    io_limits.iops[BLOCK_IO_LIMIT_TOTAL]= iops;
+    io_limits.iops[BLOCK_IO_LIMIT_READ] = iops_rd;
+    io_limits.iops[BLOCK_IO_LIMIT_WRITE]= iops_wr;
 
     if (!do_check_io_limits(&io_limits)) {
-        qerror_report(QERR_INVALID_PARAMETER_COMBINATION);
-        return -1;
+        error_set(errp, QERR_INVALID_PARAMETER_COMBINATION);
+        return;
     }
 
     bs->io_limits = io_limits;
@@ -829,8 +812,6 @@ int do_block_set_io_throttle(Monitor *mon,
             qemu_mod_timer(bs->block_timer, qemu_get_clock_ns(vm_clock));
         }
     }
-
-    return 0;
 }
 
 int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
diff --git a/blockdev.h b/blockdev.h
index b077449..260e16b 100644
--- a/blockdev.h
+++ b/blockdev.h
@@ -62,6 +62,4 @@ void qmp_change_blockdev(const char *device, const char *filename,
                          bool has_format, const char *format, Error **errp);
 void do_commit(Monitor *mon, const QDict *qdict);
 int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
-int do_block_set_io_throttle(Monitor *mon,
-                             const QDict *qdict, QObject **ret_data);
 #endif
diff --git a/hmp-commands.hx b/hmp-commands.hx
index ac27ab3..e6506fc 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1202,8 +1202,7 @@ ETEXI
         .args_type  = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l",
         .params     = "device bps bps_rd bps_wr iops iops_rd iops_wr",
         .help       = "change I/O throttle limits for a block drive",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_block_set_io_throttle,
+        .mhandler.cmd = hmp_block_set_io_throttle,
     },
 
 STEXI
diff --git a/hmp.c b/hmp.c
index 2b948aa..4664dbe 100644
--- a/hmp.c
+++ b/hmp.c
@@ -769,3 +769,17 @@ void hmp_change(Monitor *mon, const QDict *qdict)
     }
     hmp_handle_error(mon, &err);
 }
+
+void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
+{
+    Error *err = NULL;
+
+    qmp_block_set_io_throttle(qdict_get_str(qdict, "device"),
+                              qdict_get_int(qdict, "bps"),
+                              qdict_get_int(qdict, "bps_rd"),
+                              qdict_get_int(qdict, "bps_wr"),
+                              qdict_get_int(qdict, "iops"),
+                              qdict_get_int(qdict, "iops_rd"),
+                              qdict_get_int(qdict, "iops_wr"), &err);
+    hmp_handle_error(mon, &err);
+}
diff --git a/hmp.h b/hmp.h
index 621bdc2..aab0b1f 100644
--- a/hmp.h
+++ b/hmp.h
@@ -53,5 +53,6 @@ void hmp_set_password(Monitor *mon, const QDict *qdict);
 void hmp_expire_password(Monitor *mon, const QDict *qdict);
 void hmp_eject(Monitor *mon, const QDict *qdict);
 void hmp_change(Monitor *mon, const QDict *qdict);
+void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index eb20dac..9b154cc 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1402,3 +1402,32 @@
 ##
 { 'command': 'change',
   'data': {'device': 'str', 'target': 'str', '*arg': 'str'} }
+
+##
+# @block_set_io_throttle:
+#
+# Change I/O throttle limits for a block drive.
+#
+# @device: The name of the device
+#
+# @bps: total throughput limit in bytes per second
+#
+# @bps_rd: read throughput limit in bytes per second
+#
+# @bps_wr: write throughput limit in bytes per second
+#
+# @iops: total I/O operations per second
+#
+# @ops_rd: read I/O operations per second
+#
+# @iops_wr: write I/O operations per second
+#
+# Returns: Nothing on success
+#          If @device is not a valid block device, DeviceNotFound
+#          If the argument combination is invalid, InvalidParameterCombination
+#
+# Since: 1.1
+## 
+{ 'command': 'block_set_io_throttle',
+  'data': { 'device': 'str', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
+            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int' } }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index bfae81f..799e655 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -807,10 +807,7 @@ EQMP
     {
         .name       = "block_set_io_throttle",
         .args_type  = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l",
-        .params     = "device bps bps_rd bps_wr iops iops_rd iops_wr",
-        .help       = "change I/O throttle limits for a block drive",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_block_set_io_throttle,
+        .mhandler.cmd_new = qmp_marshal_input_block_set_io_throttle,
     },
 
 SQMP
commit 333a96ec9fd08eaa03f8de1acc41a2851ccb8096
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Thu Dec 8 11:13:50 2011 -0200

    qapi: Convert change
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/blockdev.c b/blockdev.c
index 124fbe6..8df78ce 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -717,8 +717,31 @@ void qmp_block_passwd(const char *device, const char *password, Error **errp)
     }
 }
 
-int do_change_block(Monitor *mon, const char *device,
-                    const char *filename, const char *fmt)
+static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
+                                    int bdrv_flags, BlockDriver *drv,
+                                    const char *password, Error **errp)
+{
+    if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) {
+        error_set(errp, QERR_OPEN_FILE_FAILED, filename);
+        return;
+    }
+
+    if (bdrv_key_required(bs)) {
+        if (password) {
+            if (bdrv_set_key(bs, password) < 0) {
+                error_set(errp, QERR_INVALID_PASSWORD);
+            }
+        } else {
+            error_set(errp, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs),
+                      bdrv_get_encrypted_filename(bs));
+        }
+    } else if (password) {
+        error_set(errp, QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs));
+    }
+}
+
+void qmp_change_blockdev(const char *device, const char *filename,
+                         bool has_format, const char *format, Error **errp)
 {
     BlockDriverState *bs;
     BlockDriver *drv = NULL;
@@ -727,29 +750,28 @@ int do_change_block(Monitor *mon, const char *device,
 
     bs = bdrv_find(device);
     if (!bs) {
-        qerror_report(QERR_DEVICE_NOT_FOUND, device);
-        return -1;
+        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+        return;
     }
-    if (fmt) {
-        drv = bdrv_find_whitelisted_format(fmt);
+
+    if (format) {
+        drv = bdrv_find_whitelisted_format(format);
         if (!drv) {
-            qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt);
-            return -1;
+            error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
+            return;
         }
     }
+
     eject_device(bs, 0, &err);
     if (error_is_set(&err)) {
-        qerror_report_err(err);
-        error_free(err);
-        return -1;
+        error_propagate(errp, err);
+        return;
     }
+
     bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
     bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0;
-    if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) {
-        qerror_report(QERR_OPEN_FILE_FAILED, filename);
-        return -1;
-    }
-    return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
+
+    qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, errp);
 }
 
 /* throttling disk I/O limits */
diff --git a/blockdev.h b/blockdev.h
index 1937b28..b077449 100644
--- a/blockdev.h
+++ b/blockdev.h
@@ -11,6 +11,7 @@
 #define BLOCKDEV_H
 
 #include "block.h"
+#include "error.h"
 #include "qemu-queue.h"
 
 void blockdev_mark_auto_del(BlockDriverState *bs);
@@ -57,9 +58,9 @@ DriveInfo *drive_init(QemuOpts *arg, int default_to_scsi);
 
 DriveInfo *add_init_drive(const char *opts);
 
+void qmp_change_blockdev(const char *device, const char *filename,
+                         bool has_format, const char *format, Error **errp);
 void do_commit(Monitor *mon, const QDict *qdict);
-int do_change_block(Monitor *mon, const char *device,
-                    const char *filename, const char *fmt);
 int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
 int do_block_set_io_throttle(Monitor *mon,
                              const QDict *qdict, QObject **ret_data);
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 364623c..ac27ab3 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -107,8 +107,7 @@ ETEXI
         .args_type  = "device:B,target:F,arg:s?",
         .params     = "device filename [format]",
         .help       = "change a removable medium, optional format",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_change,
+        .mhandler.cmd = hmp_change,
     },
 
 STEXI
diff --git a/hmp.c b/hmp.c
index a0752f5..2b948aa 100644
--- a/hmp.c
+++ b/hmp.c
@@ -712,3 +712,60 @@ void hmp_eject(Monitor *mon, const QDict *qdict)
     qmp_eject(device, true, force, &err);
     hmp_handle_error(mon, &err);
 }
+
+static void hmp_change_read_arg(Monitor *mon, const char *password,
+                                void *opaque)
+{
+    qmp_change_vnc_password(password, NULL);
+    monitor_read_command(mon, 1);
+}
+
+static void cb_hmp_change_bdrv_pwd(Monitor *mon, const char *password,
+                                   void *opaque)
+{
+    Error *encryption_err = opaque;
+    Error *err = NULL;
+    const char *device;
+
+    device = error_get_field(encryption_err, "device");
+
+    qmp_block_passwd(device, password, &err);
+    hmp_handle_error(mon, &err);
+    error_free(encryption_err);
+
+    monitor_read_command(mon, 1);
+}
+
+void hmp_change(Monitor *mon, const QDict *qdict)
+{
+    const char *device = qdict_get_str(qdict, "device");
+    const char *target = qdict_get_str(qdict, "target");
+    const char *arg = qdict_get_try_str(qdict, "arg");
+    Error *err = NULL;
+
+    if (strcmp(device, "vnc") == 0 &&
+            (strcmp(target, "passwd") == 0 ||
+             strcmp(target, "password") == 0)) {
+        if (!arg) {
+            monitor_read_password(mon, hmp_change_read_arg, NULL);
+            return;
+        }
+    }
+
+    qmp_change(device, target, !!arg, arg, &err);
+    if (error_is_type(err, QERR_DEVICE_ENCRYPTED)) {
+        monitor_printf(mon, "%s (%s) is encrypted.\n",
+                       error_get_field(err, "device"),
+                       error_get_field(err, "filename"));
+        if (!monitor_get_rs(mon)) {
+            monitor_printf(mon,
+                    "terminal does not support password prompting\n");
+            error_free(err);
+            return;
+        }
+        readline_start(monitor_get_rs(mon), "Password: ", 1,
+                       cb_hmp_change_bdrv_pwd, err);
+        return;
+    }
+    hmp_handle_error(mon, &err);
+}
diff --git a/hmp.h b/hmp.h
index 29dbf93..621bdc2 100644
--- a/hmp.h
+++ b/hmp.h
@@ -52,5 +52,6 @@ void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
 void hmp_set_password(Monitor *mon, const QDict *qdict);
 void hmp_expire_password(Monitor *mon, const QDict *qdict);
 void hmp_eject(Monitor *mon, const QDict *qdict);
+void hmp_change(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/monitor.c b/monitor.c
index f85a9d2..187083c 100644
--- a/monitor.c
+++ b/monitor.c
@@ -810,80 +810,6 @@ static void do_trace_print_events(Monitor *mon)
     trace_print_events((FILE *)mon, &monitor_fprintf);
 }
 
-#ifdef CONFIG_VNC
-static int change_vnc_password(const char *password)
-{
-    if (!password || !password[0]) {
-        if (vnc_display_disable_login(NULL)) {
-            qerror_report(QERR_SET_PASSWD_FAILED);
-            return -1;
-        }
-        return 0;
-    }
-
-    if (vnc_display_password(NULL, password) < 0) {
-        qerror_report(QERR_SET_PASSWD_FAILED);
-        return -1;
-    }
-
-    return 0;
-}
-
-static void change_vnc_password_cb(Monitor *mon, const char *password,
-                                   void *opaque)
-{
-    change_vnc_password(password);
-    monitor_read_command(mon, 1);
-}
-
-static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
-{
-    if (strcmp(target, "passwd") == 0 ||
-        strcmp(target, "password") == 0) {
-        if (arg) {
-            char password[9];
-            strncpy(password, arg, sizeof(password));
-            password[sizeof(password) - 1] = '\0';
-            return change_vnc_password(password);
-        } else {
-            return monitor_read_password(mon, change_vnc_password_cb, NULL);
-        }
-    } else {
-        if (vnc_display_open(NULL, target) < 0) {
-            qerror_report(QERR_VNC_SERVER_FAILED, target);
-            return -1;
-        }
-    }
-
-    return 0;
-}
-#else
-static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
-{
-    qerror_report(QERR_FEATURE_DISABLED, "vnc");
-    return -ENODEV;
-}
-#endif
-
-/**
- * do_change(): Change a removable medium, or VNC configuration
- */
-static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    const char *device = qdict_get_str(qdict, "device");
-    const char *target = qdict_get_str(qdict, "target");
-    const char *arg = qdict_get_try_str(qdict, "arg");
-    int ret;
-
-    if (strcmp(device, "vnc") == 0) {
-        ret = do_change_vnc(mon, target, arg);
-    } else {
-        ret = do_change_block(mon, device, target, arg);
-    }
-
-    return ret;
-}
-
 static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     const char *protocol  = qdict_get_str(qdict, "protocol");
diff --git a/qapi-schema.json b/qapi-schema.json
index fe935a9..eb20dac 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1366,3 +1366,39 @@
 #         string.  Existing clients are unaffected by executing this command.
 ##
 { 'command': 'change-vnc-password', 'data': {'password': 'str'} }
+
+##
+# @change:
+#
+# This command is multiple commands multiplexed together.
+#
+# @device: This is normally the name of a block device but it may also be 'vnc'.
+#          when it's 'vnc', then sub command depends on @target
+#
+# @target: If @device is a block device, then this is the new filename.
+#          If @device is 'vnc', then if the value 'password' selects the vnc
+#          change password command.   Otherwise, this specifies a new server URI
+#          address to listen to for VNC connections.
+#
+# @arg:    If @device is a block device, then this is an optional format to open
+#          the device with.
+#          If @device is 'vnc' and @target is 'password', this is the new VNC
+#          password to set.  If this argument is an empty string, then no future
+#          logins will be allowed.
+#
+# Returns: Nothing on success.
+#          If @device is not a valid block device, DeviceNotFound
+#          If @format is not a valid block format, InvalidBlockFormat
+#          If the new block device is encrypted, DeviceEncrypted.  Note that
+#          if this error is returned, the device has been opened successfully
+#          and an additional call to @block_passwd is required to set the
+#          device's password.  The behavior of reads and writes to the block
+#          device between when these calls are executed is undefined.
+#
+# Notes:  It is strongly recommended that this interface is not used especially
+#         for changing block devices.
+#
+# Since: 0.14.0
+##
+{ 'command': 'change',
+  'data': {'device': 'str', 'target': 'str', '*arg': 'str'} }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 886d589..bfae81f 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -110,10 +110,7 @@ EQMP
     {
         .name       = "change",
         .args_type  = "device:B,target:F,arg:s?",
-        .params     = "device filename [format]",
-        .help       = "change a removable medium, optional format",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_change,
+        .mhandler.cmd_new = qmp_marshal_input_change,
     },
 
 SQMP
diff --git a/qmp.c b/qmp.c
index 9c9ea62..1222b6c 100644
--- a/qmp.c
+++ b/qmp.c
@@ -23,6 +23,7 @@
 #include "hw/qdev.h"
 #include "qapi/qmp-input-visitor.h"
 #include "qapi/qmp-output-visitor.h"
+#include "blockdev.h"
 
 NameInfo *qmp_query_name(Error **errp)
 {
@@ -345,9 +346,52 @@ void qmp_expire_password(const char *protocol, const char *whenstr,
     error_set(errp, QERR_INVALID_PARAMETER, "protocol");
 }
 
+#ifdef CONFIG_VNC
 void qmp_change_vnc_password(const char *password, Error **errp)
 {
     if (vnc_display_password(NULL, password) < 0) {
         error_set(errp, QERR_SET_PASSWD_FAILED);
     }
 }
+
+static void qmp_change_vnc_listen(const char *target, Error **err)
+{
+    if (vnc_display_open(NULL, target) < 0) {
+        error_set(err, QERR_VNC_SERVER_FAILED, target);
+    }
+}
+
+static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
+                           Error **errp)
+{
+    if (strcmp(target, "passwd") == 0 || strcmp(target, "password") == 0) {
+        if (!has_arg) {
+            error_set(errp, QERR_MISSING_PARAMETER, "password");
+        } else {
+            qmp_change_vnc_password(arg, errp);
+        }
+    } else {
+        qmp_change_vnc_listen(target, errp);
+    }
+}
+#else
+void qmp_change_vnc_password(const char *password, Error **errp)
+{
+    error_set(errp, QERR_FEATURE_DISABLED, "vnc");
+}
+static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
+                           Error **errp)
+{
+    error_set(errp, QERR_FEATURE_DISABLED, "vnc");
+}
+#endif /* !CONFIG_VNC */
+
+void qmp_change(const char *device, const char *target,
+                bool has_arg, const char *arg, Error **err)
+{
+    if (strcmp(device, "vnc") == 0) {
+        qmp_change_vnc(target, has_arg, arg, err);
+    } else {
+        qmp_change_blockdev(device, target, has_arg, arg, err);
+    }
+}
commit 903a881481745584b538591ea4db92bca7156956
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Tue Dec 13 17:18:30 2011 -0200

    qerror: Extend QERR_DEVICE_ENCRYPTED
    
    Include the name of the encrypted file.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/monitor.c b/monitor.c
index bd4bc4f..f85a9d2 100644
--- a/monitor.c
+++ b/monitor.c
@@ -4682,7 +4682,8 @@ int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
     }
 
     if (monitor_ctrl_mode(mon)) {
-        qerror_report(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs));
+        qerror_report(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs),
+                      bdrv_get_encrypted_filename(bs));
         return -1;
     }
 
diff --git a/qerror.h b/qerror.h
index efda232..27800fe 100644
--- a/qerror.h
+++ b/qerror.h
@@ -70,7 +70,7 @@ QError *qobject_to_qerror(const QObject *obj);
     "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }"
 
 #define QERR_DEVICE_ENCRYPTED \
-    "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s } }"
+    "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }"
 
 #define QERR_DEVICE_INIT_FAILED \
     "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }"
diff --git a/qmp.c b/qmp.c
index f218485..9c9ea62 100644
--- a/qmp.c
+++ b/qmp.c
@@ -135,7 +135,8 @@ static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs)
     Error **err = opaque;
 
     if (!error_is_set(err) && bdrv_key_required(bs)) {
-        error_set(err, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs));
+        error_set(err, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs),
+                  bdrv_get_encrypted_filename(bs));
     }
 }
 
commit 270b243f91cdae380eb02396e57452c15dbcef86
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Thu Dec 8 11:45:55 2011 -0200

    qapi: Introduce change-vnc-password
    
    New QMP command to change the VNC password.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/qapi-schema.json b/qapi-schema.json
index 42682eb..fe935a9 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1352,3 +1352,17 @@
 # Since: 0.14.0
 ##
 { 'command': 'eject', 'data': {'device': 'str', '*force': 'bool'} }
+
+##
+# @change-vnc-password:
+#
+# Change the VNC server password.
+#
+# @target:  the new password to use with VNC authentication
+#
+# Since: 1.1
+#
+# Notes:  An empty password in this command will set the password to the empty
+#         string.  Existing clients are unaffected by executing this command.
+##
+{ 'command': 'change-vnc-password', 'data': {'password': 'str'} }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 185beba..886d589 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2018,3 +2018,9 @@ EQMP
 	.args_type  = "path:s,property:s",
 	.mhandler.cmd_new = qmp_qom_get,
     },
+
+    {
+        .name       = "change-vnc-password",
+        .args_type  = "password:s",
+        .mhandler.cmd_new = qmp_marshal_input_change_vnc_password,
+    },
diff --git a/qmp.c b/qmp.c
index 8b7b379..f218485 100644
--- a/qmp.c
+++ b/qmp.c
@@ -343,3 +343,10 @@ void qmp_expire_password(const char *protocol, const char *whenstr,
 
     error_set(errp, QERR_INVALID_PARAMETER, "protocol");
 }
+
+void qmp_change_vnc_password(const char *password, Error **errp)
+{
+    if (vnc_display_password(NULL, password) < 0) {
+        error_set(errp, QERR_SET_PASSWD_FAILED);
+    }
+}
commit 7060b478d3f3a8bc7a282292609ff5aec6de1958
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Sep 2 12:34:50 2011 -0500

    monitor: expose readline state
    
    HMP is now implemented in terms of QMP.  The monitor has a bunch of logic to
    deal with HMP right now like readline support.  Export it from the monitor so
    we can consume it in hmp.c.
    
    In short time, hmp.c will take over all of the readline bits.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/monitor.c b/monitor.c
index aa7259c..bd4bc4f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -227,7 +227,7 @@ int monitor_cur_is_qmp(void)
     return cur_mon && monitor_ctrl_mode(cur_mon);
 }
 
-static void monitor_read_command(Monitor *mon, int show_prompt)
+void monitor_read_command(Monitor *mon, int show_prompt)
 {
     if (!mon->rs)
         return;
@@ -237,8 +237,8 @@ static void monitor_read_command(Monitor *mon, int show_prompt)
         readline_show_prompt(mon->rs);
 }
 
-static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
-                                 void *opaque)
+int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
+                          void *opaque)
 {
     if (monitor_ctrl_mode(mon)) {
         qerror_report(QERR_MISSING_PARAMETER, "password");
@@ -4664,6 +4664,11 @@ static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)
     monitor_read_command(mon, 1);
 }
 
+ReadLineState *monitor_get_rs(Monitor *mon)
+{
+    return mon->rs;
+}
+
 int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
                                 BlockDriverCompletionFunc *completion_cb,
                                 void *opaque)
diff --git a/monitor.h b/monitor.h
index cfa2f67..887c472 100644
--- a/monitor.h
+++ b/monitor.h
@@ -6,6 +6,7 @@
 #include "qerror.h"
 #include "qdict.h"
 #include "block.h"
+#include "readline.h"
 
 extern Monitor *cur_mon;
 extern Monitor *default_mon;
@@ -66,6 +67,10 @@ int monitor_get_cpu_index(void);
 typedef void (MonitorCompletion)(void *opaque, QObject *ret_data);
 
 void monitor_set_error(Monitor *mon, QError *qerror);
+void monitor_read_command(Monitor *mon, int show_prompt);
+ReadLineState *monitor_get_rs(Monitor *mon);
+int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
+                          void *opaque);
 
 int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret);
 
commit c245b6a37d76670c3ba7b9063bac943bb998bb7c
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Wed Dec 7 16:02:36 2011 -0200

    qapi: Convert eject
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/blockdev.c b/blockdev.c
index 9ee5bae..124fbe6 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -683,27 +683,17 @@ static void eject_device(BlockDriverState *bs, int force, Error **errp)
     bdrv_close(bs);
 }
 
-int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
+void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
 {
     BlockDriverState *bs;
-    int force = qdict_get_try_bool(qdict, "force", 0);
-    const char *filename = qdict_get_str(qdict, "device");
-    Error *err = NULL;
 
-    bs = bdrv_find(filename);
+    bs = bdrv_find(device);
     if (!bs) {
-        qerror_report(QERR_DEVICE_NOT_FOUND, filename);
-        return -1;
-    }
-
-    eject_device(bs, force, &err);
-    if (error_is_set(&err)) {
-        qerror_report_err(err);
-        error_free(err);
-        return -1;
+        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+        return;
     }
 
-    return 0;
+    eject_device(bs, force, errp);
 }
 
 void qmp_block_passwd(const char *device, const char *password, Error **errp)
diff --git a/blockdev.h b/blockdev.h
index f1b6396..1937b28 100644
--- a/blockdev.h
+++ b/blockdev.h
@@ -58,7 +58,6 @@ DriveInfo *drive_init(QemuOpts *arg, int default_to_scsi);
 DriveInfo *add_init_drive(const char *opts);
 
 void do_commit(Monitor *mon, const QDict *qdict);
-int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data);
 int do_change_block(Monitor *mon, const char *device,
                     const char *filename, const char *fmt);
 int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 047fba2..364623c 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -75,8 +75,7 @@ ETEXI
         .args_type  = "force:-f,device:B",
         .params     = "[-f] device",
         .help       = "eject a removable medium (use -f to force it)",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_eject,
+        .mhandler.cmd = hmp_eject,
     },
 
 STEXI
diff --git a/hmp.c b/hmp.c
index 081acab..a0752f5 100644
--- a/hmp.c
+++ b/hmp.c
@@ -702,3 +702,13 @@ void hmp_expire_password(Monitor *mon, const QDict *qdict)
     qmp_expire_password(protocol, whenstr, &err);
     hmp_handle_error(mon, &err);
 }
+
+void hmp_eject(Monitor *mon, const QDict *qdict)
+{
+    int force = qdict_get_try_bool(qdict, "force", 0);
+    const char *device = qdict_get_str(qdict, "device");
+    Error *err = NULL;
+
+    qmp_eject(device, true, force, &err);
+    hmp_handle_error(mon, &err);
+}
diff --git a/hmp.h b/hmp.h
index 575f529..29dbf93 100644
--- a/hmp.h
+++ b/hmp.h
@@ -51,5 +51,6 @@ void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
 void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
 void hmp_set_password(Monitor *mon, const QDict *qdict);
 void hmp_expire_password(Monitor *mon, const QDict *qdict);
+void hmp_eject(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index dc92a79..42682eb 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1331,3 +1331,24 @@
 #        sure you are on the same machine as the QEMU instance.
 ##
 { 'command': 'expire_password', 'data': {'protocol': 'str', 'time': 'str'} }
+
+##
+# @eject:
+#
+# Ejects a device from a removable drive.
+#
+# @device:  The name of the device
+#
+# @force:   @optional If true, eject regardless of whether the drive is locked.
+#           If not specified, the default value is false.
+#
+# Returns:  Nothing on success
+#           If @device is not a valid block device, DeviceNotFound
+#           If @device is not removable and @force is false, DeviceNotRemovable
+#           If @force is false and @device is locked, DeviceLocked
+#
+# Notes:    Ejecting a device will no media results in success
+#
+# Since: 0.14.0
+##
+{ 'command': 'eject', 'data': {'device': 'str', '*force': 'bool'} }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index d7264b2..185beba 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -84,10 +84,7 @@ EQMP
     {
         .name       = "eject",
         .args_type  = "force:-f,device:B",
-        .params     = "[-f] device",
-        .help       = "eject a removable medium (use -f to force it)",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_eject,
+        .mhandler.cmd_new = qmp_marshal_input_eject,
     },
 
 SQMP
commit 92d48558edb14666a2851068db4c2095664e0fbc
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Wed Dec 7 15:47:23 2011 -0200

    block: eject_device(): Use error_set()
    
    Also drops the leftover 'mon' argument.
    
    This is a preparation for the next commits which will port the
    eject and change commands to the QAPI.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/blockdev.c b/blockdev.c
index c832782..9ee5bae 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -665,21 +665,22 @@ void qmp_blockdev_snapshot_sync(const char *device, const char *snapshot_file,
     }
 }
 
-static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
+static void eject_device(BlockDriverState *bs, int force, Error **errp)
 {
     if (!bdrv_dev_has_removable_media(bs)) {
-        qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
-        return -1;
+        error_set(errp, QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
+        return;
     }
+
     if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
         bdrv_dev_eject_request(bs, force);
         if (!force) {
-            qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
-            return -1;
+            error_set(errp, QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
+            return;
         }
     }
+
     bdrv_close(bs);
-    return 0;
 }
 
 int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
@@ -687,13 +688,22 @@ int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
     BlockDriverState *bs;
     int force = qdict_get_try_bool(qdict, "force", 0);
     const char *filename = qdict_get_str(qdict, "device");
+    Error *err = NULL;
 
     bs = bdrv_find(filename);
     if (!bs) {
         qerror_report(QERR_DEVICE_NOT_FOUND, filename);
         return -1;
     }
-    return eject_device(mon, bs, force);
+
+    eject_device(bs, force, &err);
+    if (error_is_set(&err)) {
+        qerror_report_err(err);
+        error_free(err);
+        return -1;
+    }
+
+    return 0;
 }
 
 void qmp_block_passwd(const char *device, const char *password, Error **errp)
@@ -723,6 +733,7 @@ int do_change_block(Monitor *mon, const char *device,
     BlockDriverState *bs;
     BlockDriver *drv = NULL;
     int bdrv_flags;
+    Error *err = NULL;
 
     bs = bdrv_find(device);
     if (!bs) {
@@ -736,7 +747,10 @@ int do_change_block(Monitor *mon, const char *device,
             return -1;
         }
     }
-    if (eject_device(mon, bs, 0) < 0) {
+    eject_device(bs, 0, &err);
+    if (error_is_set(&err)) {
+        qerror_report_err(err);
+        error_free(err);
         return -1;
     }
     bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
commit 9ad5372daa3100d78b12aad59054970f15692a90
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Wed Dec 7 11:47:57 2011 -0200

    qapi: Convert expire_password
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/console.h b/console.h
index be3b7c8..6ba0d5d 100644
--- a/console.h
+++ b/console.h
@@ -4,7 +4,6 @@
 #include "qemu-char.h"
 #include "qdict.h"
 #include "notify.h"
-#include "qerror.h"
 #include "monitor.h"
 
 /* keyboard/mouse support */
@@ -388,7 +387,6 @@ static inline int vnc_display_password(DisplayState *ds, const char *password)
 }
 static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
 {
-    qerror_report(QERR_FEATURE_DISABLED, "vnc");
     return -ENODEV;
 };
 #endif
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 4355a6f..047fba2 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1239,8 +1239,7 @@ ETEXI
         .args_type  = "protocol:s,time:s",
         .params     = "protocol time",
         .help       = "set spice/vnc password expire-time",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = expire_password,
+        .mhandler.cmd = hmp_expire_password,
     },
 
 STEXI
diff --git a/hmp.c b/hmp.c
index 888e1b9..081acab 100644
--- a/hmp.c
+++ b/hmp.c
@@ -692,3 +692,13 @@ void hmp_set_password(Monitor *mon, const QDict *qdict)
     qmp_set_password(protocol, password, !!connected, connected, &err);
     hmp_handle_error(mon, &err);
 }
+
+void hmp_expire_password(Monitor *mon, const QDict *qdict)
+{
+    const char *protocol  = qdict_get_str(qdict, "protocol");
+    const char *whenstr = qdict_get_str(qdict, "time");
+    Error *err = NULL;
+
+    qmp_expire_password(protocol, whenstr, &err);
+    hmp_handle_error(mon, &err);
+}
diff --git a/hmp.h b/hmp.h
index 4ed0fee..575f529 100644
--- a/hmp.h
+++ b/hmp.h
@@ -50,5 +50,6 @@ void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
 void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
 void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
 void hmp_set_password(Monitor *mon, const QDict *qdict);
+void hmp_expire_password(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/monitor.c b/monitor.c
index 1f5d343..aa7259c 100644
--- a/monitor.c
+++ b/monitor.c
@@ -884,45 +884,6 @@ static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
     return ret;
 }
 
-static int expire_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    const char *protocol  = qdict_get_str(qdict, "protocol");
-    const char *whenstr = qdict_get_str(qdict, "time");
-    time_t when;
-    int rc;
-
-    if (strcmp(whenstr, "now") == 0) {
-        when = 0;
-    } else if (strcmp(whenstr, "never") == 0) {
-        when = TIME_MAX;
-    } else if (whenstr[0] == '+') {
-        when = time(NULL) + strtoull(whenstr+1, NULL, 10);
-    } else {
-        when = strtoull(whenstr, NULL, 10);
-    }
-
-    if (strcmp(protocol, "spice") == 0) {
-        if (!using_spice) {
-            /* correct one? spice isn't a device ,,, */
-            qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
-            return -1;
-        }
-        rc = qemu_spice_set_pw_expire(when);
-        if (rc != 0) {
-            qerror_report(QERR_SET_PASSWD_FAILED);
-            return -1;
-        }
-        return 0;
-    }
-
-    if (strcmp(protocol, "vnc") == 0) {
-        return vnc_display_pw_expire(NULL, when);
-    }
-
-    qerror_report(QERR_INVALID_PARAMETER, "protocol");
-    return -1;
-}
-
 static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     const char *protocol  = qdict_get_str(qdict, "protocol");
diff --git a/qapi-schema.json b/qapi-schema.json
index 092ff6e..dc92a79 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1304,3 +1304,30 @@
 ##
 { 'command': 'set_password',
   'data': {'protocol': 'str', 'password': 'str', '*connected': 'str'} }
+
+##
+# @expire_password:
+#
+# Expire the password of a remote display server.
+#
+# @protocol: the name of the remote display protocol `vnc' or `spice'
+#
+# @time: when to expire the password.
+#        `now' to expire the password immediately
+#        `never' to cancel password expiration
+#        `+INT' where INT is the number of seconds from now (integer)
+#        `INT' where INT is the absolute time in seconds
+#
+# Returns: Nothing on success
+#          If @protocol is `spice' and Spice is not active, DeviceNotFound
+#          If an error occurs setting password expiration, SetPasswdFailed
+#          If @protocol is not `spice' or 'vnc', InvalidParameter
+#
+# Since: 0.14.0
+#
+# Notes: Time is relative to the server and currently there is no way to
+#        coordinate server time with client time.  It is not recommended to
+#        use the absolute time version of the @time parameter unless you're
+#        sure you are on the same machine as the QEMU instance.
+##
+{ 'command': 'expire_password', 'data': {'protocol': 'str', 'time': 'str'} }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index eadad05..d7264b2 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -877,10 +877,7 @@ EQMP
     {
         .name       = "expire_password",
         .args_type  = "protocol:s,time:s",
-        .params     = "protocol time",
-        .help       = "set spice/vnc password expire-time",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = expire_password,
+        .mhandler.cmd_new = qmp_marshal_input_expire_password,
     },
 
 SQMP
diff --git a/qmp.c b/qmp.c
index 9ef43a8..8b7b379 100644
--- a/qmp.c
+++ b/qmp.c
@@ -303,3 +303,43 @@ void qmp_set_password(const char *protocol, const char *password,
 
     error_set(errp, QERR_INVALID_PARAMETER, "protocol");
 }
+
+void qmp_expire_password(const char *protocol, const char *whenstr,
+                         Error **errp)
+{
+    time_t when;
+    int rc;
+
+    if (strcmp(whenstr, "now") == 0) {
+        when = 0;
+    } else if (strcmp(whenstr, "never") == 0) {
+        when = TIME_MAX;
+    } else if (whenstr[0] == '+') {
+        when = time(NULL) + strtoull(whenstr+1, NULL, 10);
+    } else {
+        when = strtoull(whenstr, NULL, 10);
+    }
+
+    if (strcmp(protocol, "spice") == 0) {
+        if (!using_spice) {
+            /* correct one? spice isn't a device ,,, */
+            error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice");
+            return;
+        }
+        rc = qemu_spice_set_pw_expire(when);
+        if (rc != 0) {
+            error_set(errp, QERR_SET_PASSWD_FAILED);
+        }
+        return;
+    }
+
+    if (strcmp(protocol, "vnc") == 0) {
+        rc = vnc_display_pw_expire(NULL, when);
+        if (rc != 0) {
+            error_set(errp, QERR_SET_PASSWD_FAILED);
+        }
+        return;
+    }
+
+    error_set(errp, QERR_INVALID_PARAMETER, "protocol");
+}
commit fbf796fd6f855313d2c02b7d8e1a0c4241b1e0b6
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Wed Dec 7 11:17:51 2011 -0200

    qapi: Convert set_password
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/hmp-commands.hx b/hmp-commands.hx
index a586498..4355a6f 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1219,8 +1219,7 @@ ETEXI
         .args_type  = "protocol:s,password:s,connected:s?",
         .params     = "protocol password action-if-connected",
         .help       = "set spice/vnc password",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = set_password,
+        .mhandler.cmd = hmp_set_password,
     },
 
 STEXI
diff --git a/hmp.c b/hmp.c
index 8a77780..888e1b9 100644
--- a/hmp.c
+++ b/hmp.c
@@ -681,3 +681,14 @@ void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
     int64_t value = qdict_get_int(qdict, "value");
     qmp_migrate_set_speed(value, NULL);
 }
+
+void hmp_set_password(Monitor *mon, const QDict *qdict)
+{
+    const char *protocol  = qdict_get_str(qdict, "protocol");
+    const char *password  = qdict_get_str(qdict, "password");
+    const char *connected = qdict_get_try_str(qdict, "connected");
+    Error *err = NULL;
+
+    qmp_set_password(protocol, password, !!connected, connected, &err);
+    hmp_handle_error(mon, &err);
+}
diff --git a/hmp.h b/hmp.h
index 093242d..4ed0fee 100644
--- a/hmp.h
+++ b/hmp.h
@@ -49,5 +49,6 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
 void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
 void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
 void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
+void hmp_set_password(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/monitor.c b/monitor.c
index 759c133..1f5d343 100644
--- a/monitor.c
+++ b/monitor.c
@@ -884,63 +884,6 @@ static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
     return ret;
 }
 
-static int set_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    const char *protocol  = qdict_get_str(qdict, "protocol");
-    const char *password  = qdict_get_str(qdict, "password");
-    const char *connected = qdict_get_try_str(qdict, "connected");
-    int disconnect_if_connected = 0;
-    int fail_if_connected = 0;
-    int rc;
-
-    if (connected) {
-        if (strcmp(connected, "fail") == 0) {
-            fail_if_connected = 1;
-        } else if (strcmp(connected, "disconnect") == 0) {
-            disconnect_if_connected = 1;
-        } else if (strcmp(connected, "keep") == 0) {
-            /* nothing */
-        } else {
-            qerror_report(QERR_INVALID_PARAMETER, "connected");
-            return -1;
-        }
-    }
-
-    if (strcmp(protocol, "spice") == 0) {
-        if (!using_spice) {
-            /* correct one? spice isn't a device ,,, */
-            qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
-            return -1;
-        }
-        rc = qemu_spice_set_passwd(password, fail_if_connected,
-                                   disconnect_if_connected);
-        if (rc != 0) {
-            qerror_report(QERR_SET_PASSWD_FAILED);
-            return -1;
-        }
-        return 0;
-    }
-
-    if (strcmp(protocol, "vnc") == 0) {
-        if (fail_if_connected || disconnect_if_connected) {
-            /* vnc supports "connected=keep" only */
-            qerror_report(QERR_INVALID_PARAMETER, "connected");
-            return -1;
-        }
-        /* Note that setting an empty password will not disable login through
-         * this interface. */
-        rc = vnc_display_password(NULL, password);
-        if (rc < 0) {
-            qerror_report(QERR_SET_PASSWD_FAILED);
-            return -1;
-        }
-        return 0;
-    }
-
-    qerror_report(QERR_INVALID_PARAMETER, "protocol");
-    return -1;
-}
-
 static int expire_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     const char *protocol  = qdict_get_str(qdict, "protocol");
diff --git a/qapi-schema.json b/qapi-schema.json
index 44cf764..092ff6e 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1275,3 +1275,32 @@
 { 'command': 'qom-set',
   'data': { 'path': 'str', 'property': 'str', 'value': 'visitor' },
   'gen': 'no' }
+
+##
+# @set_password:
+#
+# Sets the password of a remote display session.
+#
+# @protocol: `vnc' to modify the VNC server password
+#            `spice' to modify the Spice server password
+#
+# @password: the new password
+#
+# @connected: #optional how to handle existing clients when changing the
+#                       password.  If nothing is specified, defaults to `keep' 
+#                       `fail' to fail the command if clients are connected
+#                       `disconnect' to disconnect existing clients
+#                       `keep' to maintain existing clients
+#
+# Returns: Nothing on success
+#          If Spice is not enabled, DeviceNotFound
+#          If @protocol does not support connected, InvalidParameter
+#          If @protocol is invalid, InvalidParameter
+#          If any other error occurs, SetPasswdFailed
+#
+# Notes: If VNC is not enabled, SetPasswdFailed is returned.
+#
+# Since: 0.14.0
+##
+{ 'command': 'set_password',
+  'data': {'protocol': 'str', 'password': 'str', '*connected': 'str'} }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 7e3f4b9..eadad05 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -851,10 +851,7 @@ EQMP
     {
         .name       = "set_password",
         .args_type  = "protocol:s,password:s,connected:s?",
-        .params     = "protocol password action-if-connected",
-        .help       = "set spice/vnc password",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = set_password,
+        .mhandler.cmd_new = qmp_marshal_input_set_password,
     },
 
 SQMP
diff --git a/qmp.c b/qmp.c
index c74dde6..9ef43a8 100644
--- a/qmp.c
+++ b/qmp.c
@@ -16,6 +16,8 @@
 #include "qemu-common.h"
 #include "sysemu.h"
 #include "qmp-commands.h"
+#include "ui/qemu-spice.h"
+#include "ui/vnc.h"
 #include "kvm.h"
 #include "arch_init.h"
 #include "hw/qdev.h"
@@ -249,3 +251,55 @@ out:
 
     return 0;
 }
+
+void qmp_set_password(const char *protocol, const char *password,
+                      bool has_connected, const char *connected, Error **errp)
+{
+    int disconnect_if_connected = 0;
+    int fail_if_connected = 0;
+    int rc;
+
+    if (has_connected) {
+        if (strcmp(connected, "fail") == 0) {
+            fail_if_connected = 1;
+        } else if (strcmp(connected, "disconnect") == 0) {
+            disconnect_if_connected = 1;
+        } else if (strcmp(connected, "keep") == 0) {
+            /* nothing */
+        } else {
+            error_set(errp, QERR_INVALID_PARAMETER, "connected");
+            return;
+        }
+    }
+
+    if (strcmp(protocol, "spice") == 0) {
+        if (!using_spice) {
+            /* correct one? spice isn't a device ,,, */
+            error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice");
+            return;
+        }
+        rc = qemu_spice_set_passwd(password, fail_if_connected,
+                                   disconnect_if_connected);
+        if (rc != 0) {
+            error_set(errp, QERR_SET_PASSWD_FAILED);
+        }
+        return;
+    }
+
+    if (strcmp(protocol, "vnc") == 0) {
+        if (fail_if_connected || disconnect_if_connected) {
+            /* vnc supports "connected=keep" only */
+            error_set(errp, QERR_INVALID_PARAMETER, "connected");
+            return;
+        }
+        /* Note that setting an empty password will not disable login through
+         * this interface. */
+        rc = vnc_display_password(NULL, password);
+        if (rc < 0) {
+            error_set(errp, QERR_SET_PASSWD_FAILED);
+        }
+        return;
+    }
+
+    error_set(errp, QERR_INVALID_PARAMETER, "protocol");
+}
commit a6aa9d3e2681199d159963e46524625d90669619
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Wed Dec 7 10:19:10 2011 -0200

    vnc: Simplify vnc_display_password()
    
    Drop the qerror_report() call from it and let its callers set the error
    themselves. This also allows for dropping the 'ret' variable.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/console.h b/console.h
index 9466886..be3b7c8 100644
--- a/console.h
+++ b/console.h
@@ -384,7 +384,6 @@ int vnc_display_pw_expire(DisplayState *ds, time_t expires);
 #else
 static inline int vnc_display_password(DisplayState *ds, const char *password)
 {
-    qerror_report(QERR_FEATURE_DISABLED, "vnc");
     return -ENODEV;
 }
 static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
diff --git a/monitor.c b/monitor.c
index 7334401..759c133 100644
--- a/monitor.c
+++ b/monitor.c
@@ -929,7 +929,12 @@ static int set_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
         }
         /* Note that setting an empty password will not disable login through
          * this interface. */
-        return vnc_display_password(NULL, password);
+        rc = vnc_display_password(NULL, password);
+        if (rc < 0) {
+            qerror_report(QERR_SET_PASSWD_FAILED);
+            return -1;
+        }
+        return 0;
     }
 
     qerror_report(QERR_INVALID_PARAMETER, "protocol");
diff --git a/ui/vnc.c b/ui/vnc.c
index 1869a7a..16b79ec 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2686,19 +2686,16 @@ int vnc_display_disable_login(DisplayState *ds)
 
 int vnc_display_password(DisplayState *ds, const char *password)
 {
-    int ret = 0;
     VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
 
     if (!vs) {
-        ret = -EINVAL;
-        goto out;
+        return -EINVAL;
     }
 
     if (!password) {
         /* This is not the intention of this interface but err on the side
            of being safe */
-        ret = vnc_display_disable_login(ds);
-        goto out;
+        return vnc_display_disable_login(ds);
     }
 
     if (vs->password) {
@@ -2707,11 +2704,8 @@ int vnc_display_password(DisplayState *ds, const char *password)
     }
     vs->password = g_strdup(password);
     vs->auth = VNC_AUTH_VNC;
-out:
-    if (ret != 0) {
-        qerror_report(QERR_SET_PASSWD_FAILED);
-    }
-    return ret;
+
+    return 0;
 }
 
 int vnc_display_pw_expire(DisplayState *ds, time_t expires)
commit 6b7332eb4013fec6ad294115ab889d77d4463624
Author: Markus Armbruster <armbru at redhat.com>
Date:   Fri Nov 4 10:34:24 2011 +0100

    qxl: Slot sanity check in qxl_phys2virt() is off by one, fix
    
    Spotted by Coverity.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index ac81927..bdd36f9 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1020,7 +1020,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;
commit a32134aad891bd7b6cfa72b8f5ae2290bbe6fdda
Author: Mark Langsdorf <mark.langsdorf at calxeda.com>
Date:   Tue Jan 17 10:54:07 2012 +0000

    arm: make the number of GIC interrupts configurable
    
    Increase the maximum number of GIC interrupts for a9mp and a11mp to 1020,
    and create a configurable property for each defaulting to 96 and 64
    (respectively) so that device modelers can set the value appropriately
    for their SoC. Other ARM processors also set their maximum number of
    used IRQs appropriately.
    
    Set the maximum theoretical number of GIC interrupts to 1020 and
    update the save/restore code to only use the appropriate number for
    each SoC.
    
    Signed-off-by: Mark Langsdorf <mark.langsdorf at calxeda.com>
    Reviewed-by: Andreas Färber <afaerber at suse.de>
    [Peter Maydell: fixed minor whitespace snafu]
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index 3ef0e13..521b8cc 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);
@@ -216,6 +216,13 @@ static SysBusDeviceInfo a9mp_priv_info = {
     .qdev.reset = a9mp_priv_reset,
     .qdev.props = (Property[]) {
         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(),
     }
 };
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index bc0457e..f4d88dc 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);
@@ -221,6 +217,15 @@ static SysBusDeviceInfo mpcore_priv_info = {
     .qdev.size  = sizeof(mpcore_priv_state),
     .qdev.props = (Property[]) {
         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(),
     }
 };
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 0339cf5..cf582a5 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/armv7m_nvic.c b/hw/armv7m_nvic.c
index bf8c3c5..28f36ba 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,33 @@ 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 SysBusDeviceInfo armv7m_nvic_priv_info = {
+    .init = armv7m_nvic_init,
+    .qdev.name  = "armv7m_nvic",
+    .qdev.size  = sizeof(nvic_state),
+    .qdev.vmsd  = &vmstate_nvic,
+    .qdev.props = (Property[]) {
+        /* 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_register_devices(void)
 {
-    sysbus_register_dev("armv7m_nvic", sizeof(nvic_state), armv7m_nvic_init);
+    sysbus_register_withprop(&armv7m_nvic_priv_info);
 }
 
 device_init(armv7m_nvic_register_devices)
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index 8c4d509..7342ede 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,7 +36,11 @@ 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;
commit b09da0c335204322ba7a806f63180984df4db6f3
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Jan 17 10:54:07 2012 +0000

    hw/lan9118: Add save/load support
    
    Implement save/load for the LAN9118.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Andreas Färber <afaerber at suse.de>

diff --git a/hw/lan9118.c b/hw/lan9118.c
index 8b83fe2..9b199d0 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;
@@ -1155,7 +1235,6 @@ static int lan9118_init1(SysBusDevice *dev)
     ptimer_set_freq(s->timer, 10000);
     ptimer_set_limit(s->timer, 0xffff, 1);
 
-    /* ??? Save/restore.  */
     return 0;
 }
 
@@ -1164,6 +1243,7 @@ static SysBusDeviceInfo lan9118_info = {
     .qdev.name  = "lan9118",
     .qdev.size  = sizeof(lan9118_state),
     .qdev.reset = lan9118_reset,
+    .qdev.vmsd = &vmstate_lan9118,
     .qdev.props = (Property[]) {
         DEFINE_NIC_PROPERTIES(lan9118_state, conf),
         DEFINE_PROP_END_OF_LIST(),
commit 100cf55ff98ce7e9b7ff3747479fa924c9e4505b
Author: Mark Langsdorf <mark.langsdorf at calxeda.com>
Date:   Tue Jan 17 10:54:07 2012 +0000

    arm: Remove incorrect comment in arm_timer
    
    The current comment says that the arm_timers are restricted to between
    32 KHz and 1 MHz, but sp804 TRM does not specify those limits.
    
    Signed-off-by: Mark Langsdorf <mark.langsdorf at calxeda.com>
    Reviewed-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 1902f1a..ead2535 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);
commit 5a15758874cfad886e637e015baa7888a0c60262
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Jan 17 10:54:07 2012 +0000

    vexpress, realview: Add (dummy) L2 cache controller
    
    Instantiate the L2 cache controller on the ARM devboards which have one,
    since we have a dummy model of it now. Note that the only non-MP board
    with an L2x0 is the PB1176, which we don't model.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/realview.c b/hw/realview.c
index 3f35118..d2fde44 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -227,6 +227,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/vexpress.c b/hw/vexpress.c
index 7111556..64fab45 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 */
commit 322135435b5c6fe47cc7596cd394e433236ee49f
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Tue Jan 10 14:13:08 2012 +0100

    usb-redir: Improve some debugging messages
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/usb-redir.c b/usb-redir.c
index 147e237..79d29ec 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -395,7 +395,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
         /* No id, we look at the ep when receiving a status back */
         usbredirparser_send_start_iso_stream(dev->parser, 0, &start_iso);
         usbredirparser_do_write(dev->parser);
-        DPRINTF("iso stream started ep %02X\n", ep);
+        DPRINTF("iso stream started pkts/sec %d pkts/urb %d urbs %d ep %02X\n",
+                pkts_per_sec, start_iso.pkts_per_urb, start_iso.no_urbs, ep);
         dev->endpoint[EP2I(ep)].iso_started = 1;
         dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
         dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
@@ -415,7 +416,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
 
         isop = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
         if (isop == NULL) {
-            DPRINTF2("iso-token-in ep %02X, no isop\n", ep);
+            DPRINTF("iso-token-in ep %02X, no isop, iso_error: %d\n",
+                    ep, dev->endpoint[EP2I(ep)].iso_error);
             /* Re-fill the buffer */
             dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
             /* Check iso_error for stream errors, otherwise its an underrun */
@@ -423,8 +425,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
             dev->endpoint[EP2I(ep)].iso_error = 0;
             return usbredir_handle_status(dev, status, 0);
         }
-        DPRINTF2("iso-token-in ep %02X status %d len %d\n", ep, isop->status,
-                 isop->len);
+        DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep,
+                 isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size);
 
         status = isop->status;
         if (status != usb_redir_success) {
@@ -434,7 +436,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
 
         len = isop->len;
         if (len > p->iov.size) {
-            ERROR("received iso data is larger then packet ep %02X\n", ep);
+            ERROR("received iso data is larger then packet ep %02X (%d > %d)\n",
+                  ep, len, (int)p->iov.size);
             bufp_free(dev, isop, ep);
             return USB_RET_NAK;
         }
commit 81fd7b7495d2a4c92483ed14075e376729c94ab4
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Tue Jan 10 14:13:07 2012 +0100

    usb-redir: Try to keep our buffer size near the target size
    
    Before this patch we would allow the (iso) buffer to grow unlimited
    (and it would under certain circumstances) leading to way too high
    latencies for iso data streams.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/usb-redir.c b/usb-redir.c
index cdd929a..147e237 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -61,6 +61,7 @@ struct endp_data {
     uint8_t interrupt_started;
     uint8_t interrupt_error;
     uint8_t bufpq_prefilled;
+    uint8_t bufpq_dropping_packets;
     QTAILQ_HEAD(, buf_packet) bufpq;
     int bufpq_size;
     int bufpq_target_size;
@@ -290,16 +291,34 @@ static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p)
     }
 }
 
-static struct buf_packet *bufp_alloc(USBRedirDevice *dev,
+static void bufp_alloc(USBRedirDevice *dev,
     uint8_t *data, int len, int status, uint8_t ep)
 {
-    struct buf_packet *bufp = g_malloc(sizeof(struct buf_packet));
+    struct buf_packet *bufp;
+
+    if (!dev->endpoint[EP2I(ep)].bufpq_dropping_packets &&
+        dev->endpoint[EP2I(ep)].bufpq_size >
+            2 * dev->endpoint[EP2I(ep)].bufpq_target_size) {
+        DPRINTF("bufpq overflow, dropping packets ep %02X\n", ep);
+        dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 1;
+    }
+    /* Since we're interupting the stream anyways, drop enough packets to get
+       back to our target buffer size */
+    if (dev->endpoint[EP2I(ep)].bufpq_dropping_packets) {
+        if (dev->endpoint[EP2I(ep)].bufpq_size >
+                dev->endpoint[EP2I(ep)].bufpq_target_size) {
+            free(data);
+            return;
+        }
+        dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
+    }
+
+    bufp = g_malloc(sizeof(struct buf_packet));
     bufp->data   = data;
     bufp->len    = len;
     bufp->status = status;
     QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
     dev->endpoint[EP2I(ep)].bufpq_size++;
-    return bufp;
 }
 
 static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp,
@@ -379,6 +398,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
         DPRINTF("iso stream started ep %02X\n", ep);
         dev->endpoint[EP2I(ep)].iso_started = 1;
         dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
+        dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
     }
 
     if (ep & USB_DIR_IN) {
@@ -505,6 +525,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
             usbredirparser_do_write(dev->parser);
             DPRINTF("interrupt recv started ep %02X\n", ep);
             dev->endpoint[EP2I(ep)].interrupt_started = 1;
+            /* We don't really want to drop interrupt packets ever, but
+               having some upper limit to how much we buffer is good. */
+            dev->endpoint[EP2I(ep)].bufpq_target_size = 1000;
+            dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
         }
 
         intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
commit e15378847919144b99ead1587a54168f1dd3ddf9
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Tue Jan 10 14:13:06 2012 +0100

    usb-redir: Pre-fill our isoc input buffer before sending pkts to the host
    
    This is something which should have been done from the first version of
    usb-redir, but wasn't.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/usb-redir.c b/usb-redir.c
index 99a12d5..cdd929a 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -60,7 +60,9 @@ struct endp_data {
     uint8_t iso_error; /* For reporting iso errors to the HC */
     uint8_t interrupt_started;
     uint8_t interrupt_error;
+    uint8_t bufpq_prefilled;
     QTAILQ_HEAD(, buf_packet) bufpq;
+    int bufpq_size;
     int bufpq_target_size;
 };
 
@@ -296,6 +298,7 @@ static struct buf_packet *bufp_alloc(USBRedirDevice *dev,
     bufp->len    = len;
     bufp->status = status;
     QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
+    dev->endpoint[EP2I(ep)].bufpq_size++;
     return bufp;
 }
 
@@ -303,6 +306,7 @@ static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp,
     uint8_t ep)
 {
     QTAILQ_REMOVE(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
+    dev->endpoint[EP2I(ep)].bufpq_size--;
     free(bufp->data);
     g_free(bufp);
 }
@@ -374,14 +378,26 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
         usbredirparser_do_write(dev->parser);
         DPRINTF("iso stream started ep %02X\n", ep);
         dev->endpoint[EP2I(ep)].iso_started = 1;
+        dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
     }
 
     if (ep & USB_DIR_IN) {
         struct buf_packet *isop;
 
+        if (dev->endpoint[EP2I(ep)].iso_started &&
+                !dev->endpoint[EP2I(ep)].bufpq_prefilled) {
+            if (dev->endpoint[EP2I(ep)].bufpq_size <
+                    dev->endpoint[EP2I(ep)].bufpq_target_size) {
+                return usbredir_handle_status(dev, 0, 0);
+            }
+            dev->endpoint[EP2I(ep)].bufpq_prefilled = 1;
+        }
+
         isop = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
         if (isop == NULL) {
             DPRINTF2("iso-token-in ep %02X, no isop\n", ep);
+            /* Re-fill the buffer */
+            dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
             /* Check iso_error for stream errors, otherwise its an underrun */
             status = dev->endpoint[EP2I(ep)].iso_error;
             dev->endpoint[EP2I(ep)].iso_error = 0;
commit e8a7dd29211dbf7e9c87fd5a56563f2940681906
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Tue Jan 10 14:13:05 2012 +0100

    usb-redir: Dynamically adjust iso buffering size based on ep interval
    
    Note the bufpq_target_size id stored in the endpoint info struct,
    even though it only used once. This is done because it will be
    referenced from other code in a follow up patch.
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/usb-redir.c b/usb-redir.c
index 81a35c6..99a12d5 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -61,6 +61,7 @@ struct endp_data {
     uint8_t interrupt_started;
     uint8_t interrupt_error;
     QTAILQ_HEAD(, buf_packet) bufpq;
+    int bufpq_target_size;
 };
 
 struct USBRedirDevice {
@@ -332,15 +333,42 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
                                      uint8_t ep)
 {
     int status, len;
-
     if (!dev->endpoint[EP2I(ep)].iso_started &&
             !dev->endpoint[EP2I(ep)].iso_error) {
         struct usb_redir_start_iso_stream_header start_iso = {
             .endpoint = ep,
-            /* TODO maybe do something with these depending on ep interval? */
-            .pkts_per_urb = 32,
-            .no_urbs = 3,
         };
+        int pkts_per_sec;
+
+        if (dev->dev.speed == USB_SPEED_HIGH) {
+            pkts_per_sec = 8000 / dev->endpoint[EP2I(ep)].interval;
+        } else {
+            pkts_per_sec = 1000 / dev->endpoint[EP2I(ep)].interval;
+        }
+        /* Testing has shown that we need circa 60 ms buffer */
+        dev->endpoint[EP2I(ep)].bufpq_target_size = (pkts_per_sec * 60) / 1000;
+
+        /* Aim for approx 100 interrupts / second on the client to
+           balance latency and interrupt load */
+        start_iso.pkts_per_urb = pkts_per_sec / 100;
+        if (start_iso.pkts_per_urb < 1) {
+            start_iso.pkts_per_urb = 1;
+        } else if (start_iso.pkts_per_urb > 32) {
+            start_iso.pkts_per_urb = 32;
+        }
+
+        start_iso.no_urbs = (dev->endpoint[EP2I(ep)].bufpq_target_size +
+                             start_iso.pkts_per_urb - 1) /
+                            start_iso.pkts_per_urb;
+        /* Output endpoints pre-fill only 1/2 of the packets, keeping the rest
+           as overflow buffer. Also see the usbredir protocol documentation */
+        if (!(ep & USB_DIR_IN)) {
+            start_iso.no_urbs *= 2;
+        }
+        if (start_iso.no_urbs > 16) {
+            start_iso.no_urbs = 16;
+        }
+
         /* No id, we look at the ep when receiving a status back */
         usbredirparser_send_start_iso_stream(dev->parser, 0, &start_iso);
         usbredirparser_do_write(dev->parser);
@@ -961,9 +989,24 @@ static void usbredir_ep_info(void *priv,
         dev->endpoint[i].type = ep_info->type[i];
         dev->endpoint[i].interval = ep_info->interval[i];
         dev->endpoint[i].interface = ep_info->interface[i];
-        if (dev->endpoint[i].type != usb_redir_type_invalid) {
+        switch (dev->endpoint[i].type) {
+        case usb_redir_type_invalid:
+            break;
+        case usb_redir_type_iso:
+        case usb_redir_type_interrupt:
+            if (dev->endpoint[i].interval == 0) {
+                ERROR("Received 0 interval for isoc or irq endpoint\n");
+                usbredir_device_disconnect(dev);
+            }
+            /* Fall through */
+        case usb_redir_type_control:
+        case usb_redir_type_bulk:
             DPRINTF("ep: %02X type: %d interface: %d\n", I2EP(i),
                     dev->endpoint[i].type, dev->endpoint[i].interface);
+            break;
+        default:
+            ERROR("Received invalid endpoint type\n");
+            usbredir_device_disconnect(dev);
         }
     }
 }
commit 2bd836e5a6b38e0e03d7f7c90c7284fb610c46eb
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Tue Jan 10 14:13:04 2012 +0100

    usb-redir: Clear iso / irq error when stopping the stream
    
    And ignore status messages from the client which arrive after stream
    stop (the stream stop send to the client and an error status reported by
    the client my cross each other due to network latency).
    
    Signed-off-by: Hans de Goede <hdegoede at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/usb-redir.c b/usb-redir.c
index 2b53cf3..81a35c6 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -410,6 +410,7 @@ static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep)
         DPRINTF("iso stream stopped ep %02X\n", ep);
         dev->endpoint[EP2I(ep)].iso_started = 0;
     }
+    dev->endpoint[EP2I(ep)].iso_error = 0;
     usbredir_free_bufpq(dev, ep);
 }
 
@@ -522,6 +523,7 @@ static void usbredir_stop_interrupt_receiving(USBRedirDevice *dev,
         DPRINTF("interrupt recv stopped ep %02X\n", ep);
         dev->endpoint[EP2I(ep)].interrupt_started = 0;
     }
+    dev->endpoint[EP2I(ep)].interrupt_error = 0;
     usbredir_free_bufpq(dev, ep);
 }
 
@@ -1029,7 +1031,7 @@ static void usbredir_iso_stream_status(void *priv, uint32_t id,
     DPRINTF("iso status %d ep %02X id %u\n", iso_stream_status->status,
             ep, id);
 
-    if (!dev->dev.attached) {
+    if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].iso_started) {
         return;
     }
 
@@ -1050,7 +1052,7 @@ static void usbredir_interrupt_receiving_status(void *priv, uint32_t id,
     DPRINTF("interrupt recv status %d ep %02X id %u\n",
             interrupt_receiving_status->status, ep, id);
 
-    if (!dev->dev.attached) {
+    if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].interrupt_started) {
         return;
     }
 
commit 25d5de7d81a5b1a5c625775648d3d92e8398741c
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Dec 13 15:58:19 2011 +0100

    usb: link packets to endpoints not devices
    
    Add USBEndpoint for the control endpoint to USBDevices.  Link async
    packets to the USBEndpoint instead of the USBDevice.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 7c926c0..a305661 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);
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 01e2e7c..4f528d2 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-ohci.c b/hw/usb-ohci.c
index 81488c4..69463d2 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;
     }
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index f8912e2..25d4e8c 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);
diff --git a/hw/usb.c b/hw/usb.c
index 0f163b4..860538a 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -329,7 +329,7 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
     ret = dev->info->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 +357,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);
+    p->owner->dev->info->cancel_packet(p->owner->dev, p);
     p->owner = NULL;
 }
 
@@ -419,11 +419,16 @@ 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;
     }
 }
 
@@ -472,6 +477,9 @@ void usb_ep_dump(USBDevice *dev)
 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;
diff --git a/hw/usb.h b/hw/usb.h
index 5ea984c..0776463 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -177,6 +177,7 @@ struct USBEndpoint {
     uint8_t type;
     uint8_t ifnum;
     int max_packet_size;
+    USBDevice *dev;
 };
 
 /* definition of a USB device */
@@ -204,6 +205,7 @@ 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];
 
@@ -317,7 +319,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);
commit f003397ce95441cd8de01a728affb3de7accd1dd
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Aug 31 16:09:27 2011 +0200

    usb: add max_packet_size to USBEndpoint
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-desc.c b/hw/usb-desc.c
index 0768334..b3eb97b 100644
--- a/hw/usb-desc.c
+++ b/hw/usb-desc.c
@@ -248,6 +248,8 @@ static void usb_desc_ep_init(USBDevice *dev)
             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);
         }
     }
 }
diff --git a/hw/usb.c b/hw/usb.c
index f07cb9d..0f163b4 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -449,8 +449,9 @@ void usb_ep_dump(USBDevice *dev)
                     fprintf(stderr, "  Interface %d, alternative %d\n",
                             ifnum, dev->altsetting[ifnum]);
                 }
-                fprintf(stderr, "    Endpoint %d, IN, %s\n", ep,
-                        tname[dev->ep_in[ep].type]);
+                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) {
@@ -459,8 +460,9 @@ void usb_ep_dump(USBDevice *dev)
                     fprintf(stderr, "  Interface %d, alternative %d\n",
                             ifnum, dev->altsetting[ifnum]);
                 }
-                fprintf(stderr, "    Endpoint %d, OUT, %s\n", ep,
-                        tname[dev->ep_out[ep].type]);
+                fprintf(stderr, "    Endpoint %d, OUT, %s, %d max\n", ep,
+                        tname[dev->ep_out[ep].type],
+                        dev->ep_out[ep].max_packet_size);
             }
         }
     }
@@ -498,3 +500,30 @@ 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 c35ff74..5ea984c 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -176,6 +176,7 @@ struct USBDescString {
 struct USBEndpoint {
     uint8_t type;
     uint8_t ifnum;
+    int max_packet_size;
 };
 
 /* definition of a USB device */
@@ -339,6 +340,9 @@ 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);
diff --git a/usb-linux.c b/usb-linux.c
index 2a7b748..56898dd 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -83,7 +83,6 @@ struct endp_data {
     AsyncURB *iso_urb;
     int iso_urb_idx;
     int iso_buffer_used;
-    int max_packet_size;
     int inflight;
 };
 
@@ -259,26 +258,6 @@ static int get_iso_buffer_used(USBHostDevice *s, int pid, int ep)
     return get_endp(s, pid, ep)->iso_buffer_used;
 }
 
-static void set_max_packet_size(USBHostDevice *s, int pid, int ep,
-                                uint8_t *descriptor)
-{
-    int raw = descriptor[4] + (descriptor[5] << 8);
-    int size, microframes;
-
-    size = raw & 0x7ff;
-    switch ((raw >> 11) & 3) {
-    case 1:  microframes = 2; break;
-    case 2:  microframes = 3; break;
-    default: microframes = 1; break;
-    }
-    get_endp(s, pid, ep)->max_packet_size = size * microframes;
-}
-
-static int get_max_packet_size(USBHostDevice *s, int pid, int ep)
-{
-    return get_endp(s, pid, ep)->max_packet_size;
-}
-
 /*
  * Async URB state.
  * We always allocate iso packet descriptors even for bulk transfers
@@ -674,7 +653,7 @@ static void usb_host_handle_destroy(USBDevice *dev)
 static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, int pid, uint8_t ep)
 {
     AsyncURB *aurb;
-    int i, j, len = get_max_packet_size(s, pid, ep);
+    int i, j, len = usb_ep_get_max_packet_size(&s->dev, pid, ep);
 
     aurb = g_malloc0(s->iso_urb_count * sizeof(*aurb));
     for (i = 0; i < s->iso_urb_count; i++) {
@@ -754,7 +733,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
     int i, j, ret, max_packet_size, offset, len = 0;
     uint8_t *buf;
 
-    max_packet_size = get_max_packet_size(s, p->pid, p->devep);
+    max_packet_size = usb_ep_get_max_packet_size(&s->dev, p->pid, p->devep);
     if (max_packet_size == 0)
         return USB_RET_NAK;
 
@@ -1133,6 +1112,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
 {
     uint8_t *descriptors;
     uint8_t devep, type, alt_interface;
+    uint16_t raw;
     int interface, length, i, ep, pid;
     struct endp_data *epd;
 
@@ -1200,9 +1180,8 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
             }
 
             type = descriptors[i + 3] & 0x3;
-            if (type == USB_ENDPOINT_XFER_ISOC) {
-                set_max_packet_size(s, pid, ep, descriptors + i);
-            };
+            raw = descriptors[i + 4] + (descriptors[i + 5] << 8);
+            usb_ep_set_max_packet_size(&s->dev, pid, ep, raw);
             assert(usb_ep_get_type(&s->dev, pid, ep) ==
                    USB_ENDPOINT_XFER_INVALID);
             usb_ep_set_type(&s->dev, pid, ep, type);
commit 5b6780d045720848c57a7cf461b49befcd24c691
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Mon Aug 29 13:45:25 2011 +0200

    usb/debug: add usb_ep_dump
    
    Add function to dump endpoint data, for debugging purposes.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb.c b/hw/usb.c
index 6ba063a..f07cb9d 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -427,6 +427,46 @@ void usb_ep_init(USBDevice *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\n", ep,
+                        tname[dev->ep_in[ep].type]);
+            }
+            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\n", ep,
+                        tname[dev->ep_out[ep].type]);
+            }
+        }
+    }
+    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;
diff --git a/hw/usb.h b/hw/usb.h
index 60e8858..c35ff74 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -333,6 +333,7 @@ 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);
diff --git a/usb-linux.c b/usb-linux.c
index cb66ef3..2a7b748 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -1214,6 +1214,9 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
             i += descriptors[i];
         }
     }
+#ifdef DEBUG
+    usb_ep_dump(&s->dev);
+#endif
     return 0;
 }
 
commit 83a53bbcdae2270656d70c7311d4f7f791532d23
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Aug 30 16:42:03 2011 +0200

    usb-desc: USBEndpoint support
    
    Initialize USBEndpoint structs from USBDesc* data.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-desc.c b/hw/usb-desc.c
index 9c38661..0768334 100644
--- a/hw/usb-desc.c
+++ b/hw/usb-desc.c
@@ -231,6 +231,27 @@ 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);
+        }
+    }
+}
+
 static const USBDescIface *usb_desc_find_interface(USBDevice *dev,
                                                    int nif, int alt)
 {
@@ -272,6 +293,7 @@ static int usb_desc_set_interface(USBDevice *dev, int index, int value)
     old = dev->altsetting[index];
     dev->altsetting[index] = value;
     dev->ifaces[index] = iface;
+    usb_desc_ep_init(dev);
 
     if (dev->info->set_interface && old != value) {
         dev->info->set_interface(dev, index, old, value);
commit 82f02fe96514605d0bb46f976871ec662193394a
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Mon Aug 29 12:57:48 2011 +0200

    usb: add ifnum to USBEndpoint
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb.c b/hw/usb.c
index 5d6baaf..6ba063a 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -422,6 +422,8 @@ void usb_ep_init(USBDevice *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;
     }
 }
 
@@ -444,3 +446,15 @@ 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;
+}
diff --git a/hw/usb.h b/hw/usb.h
index 85cbe71..60e8858 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -175,6 +175,7 @@ struct USBDescString {
 
 struct USBEndpoint {
     uint8_t type;
+    uint8_t ifnum;
 };
 
 /* definition of a USB device */
@@ -334,7 +335,9 @@ void usb_cancel_packet(USBPacket * p);
 void usb_ep_init(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_attach(USBPort *port);
 void usb_detach(USBPort *port);
diff --git a/usb-linux.c b/usb-linux.c
index 9967975..cb66ef3 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -1206,6 +1206,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
             assert(usb_ep_get_type(&s->dev, pid, ep) ==
                    USB_ENDPOINT_XFER_INVALID);
             usb_ep_set_type(&s->dev, pid, ep, type);
+            usb_ep_set_ifnum(&s->dev, pid, ep, interface);
 
             epd = get_endp(s, pid, ep);
             epd->halted = 0;
commit d8e17efdecaaa1a2d5c8f422fc44ae229e7f4fb4
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Mon Aug 29 12:49:46 2011 +0200

    usb: add USBEndpoint
    
    Start maintaining endpoint state at USBDevice level.  Add USBEndpoint
    struct and some helper functions to deal with it.  For now it contains
    the endpoint type only.  Moved over some bits from usb-linux.c
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index bd4afa7..016a3f2 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -75,6 +75,7 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
     dev->info = info;
     dev->auto_attach = 1;
     QLIST_INIT(&dev->strings);
+    usb_ep_init(dev);
     rc = usb_claim_port(dev);
     if (rc != 0) {
         return rc;
diff --git a/hw/usb.c b/hw/usb.c
index 2216efe..5d6baaf 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -414,3 +414,33 @@ void usb_packet_cleanup(USBPacket *p)
 {
     qemu_iovec_destroy(&p->iov);
 }
+
+void usb_ep_init(USBDevice *dev)
+{
+    int ep;
+
+    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;
+    }
+}
+
+struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep)
+{
+    struct USBEndpoint *eps = pid == USB_TOKEN_IN ? dev->ep_in : dev->ep_out;
+    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;
+}
diff --git a/hw/usb.h b/hw/usb.h
index b2c9479..85cbe71 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -144,6 +144,7 @@
 #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;
@@ -151,6 +152,7 @@ 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;
@@ -171,6 +173,10 @@ struct USBDescString {
 #define USB_MAX_ENDPOINTS  15
 #define USB_MAX_INTERFACES 16
 
+struct USBEndpoint {
+    uint8_t type;
+};
+
 /* definition of a USB device */
 struct USBDevice {
     DeviceState qdev;
@@ -196,6 +202,9 @@ struct USBDevice {
     int32_t setup_len;
     int32_t setup_index;
 
+    USBEndpoint ep_in[USB_MAX_ENDPOINTS];
+    USBEndpoint ep_out[USB_MAX_ENDPOINTS];
+
     QLIST_HEAD(, USBDescString) strings;
     const USBDescDevice *device;
 
@@ -322,6 +331,11 @@ 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);
+struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep);
+uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep);
+void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type);
+
 void usb_attach(USBPort *port);
 void usb_detach(USBPort *port);
 void usb_reset(USBPort *port);
diff --git a/usb-linux.c b/usb-linux.c
index ded0726..9967975 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -67,12 +67,10 @@ typedef int USBScanFunc(void *opaque, int bus_num, int addr, const char *port,
 #endif
 
 #define PRODUCT_NAME_SZ 32
-#define MAX_ENDPOINTS 15
 #define MAX_PORTLEN 16
 
 /* endpoint association data */
 #define ISO_FRAME_DESC_PER_URB 32
-#define INVALID_EP_TYPE 255
 
 /* devio.c limits single requests to 16k */
 #define MAX_USBFS_BUFFER_SIZE 16384
@@ -80,7 +78,6 @@ typedef int USBScanFunc(void *opaque, int bus_num, int addr, const char *port,
 typedef struct AsyncURB AsyncURB;
 
 struct endp_data {
-    uint8_t type;
     uint8_t halted;
     uint8_t iso_started;
     AsyncURB *iso_urb;
@@ -110,8 +107,8 @@ typedef struct USBHostDevice {
     uint32_t  iso_urb_count;
     Notifier  exit;
 
-    struct endp_data ep_in[MAX_ENDPOINTS];
-    struct endp_data ep_out[MAX_ENDPOINTS];
+    struct endp_data ep_in[USB_MAX_ENDPOINTS];
+    struct endp_data ep_out[USB_MAX_ENDPOINTS];
     QLIST_HEAD(, AsyncURB) aurbs;
 
     /* Host side address */
@@ -133,6 +130,19 @@ static int usb_host_read_file(char *line, size_t line_size,
                             const char *device_file, const char *device_name);
 static int usb_linux_update_endp_table(USBHostDevice *s);
 
+static int usb_host_usbfs_type(USBHostDevice *s, USBPacket *p)
+{
+    static const int usbfs[] = {
+        [USB_ENDPOINT_XFER_CONTROL] = USBDEVFS_URB_TYPE_CONTROL,
+        [USB_ENDPOINT_XFER_ISOC]    = USBDEVFS_URB_TYPE_ISO,
+        [USB_ENDPOINT_XFER_BULK]    = USBDEVFS_URB_TYPE_BULK,
+        [USB_ENDPOINT_XFER_INT]     = USBDEVFS_URB_TYPE_INTERRUPT,
+    };
+    uint8_t type = usb_ep_get_type(&s->dev, p->pid, p->devep);
+    assert(type < ARRAY_SIZE(usbfs));
+    return usbfs[type];
+}
+
 static int usb_host_do_reset(USBHostDevice *dev)
 {
     struct timeval s, e;
@@ -156,18 +166,18 @@ static struct endp_data *get_endp(USBHostDevice *s, int pid, int ep)
 {
     struct endp_data *eps = pid == USB_TOKEN_IN ? s->ep_in : s->ep_out;
     assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
-    assert(ep > 0 && ep <= MAX_ENDPOINTS);
+    assert(ep > 0 && ep <= USB_MAX_ENDPOINTS);
     return eps + ep - 1;
 }
 
 static int is_isoc(USBHostDevice *s, int pid, int ep)
 {
-    return get_endp(s, pid, ep)->type == USBDEVFS_URB_TYPE_ISO;
+    return usb_ep_get_type(&s->dev, pid, ep) == USB_ENDPOINT_XFER_ISOC;
 }
 
 static int is_valid(USBHostDevice *s, int pid, int ep)
 {
-    return get_endp(s, pid, ep)->type != INVALID_EP_TYPE;
+    return usb_ep_get_type(&s->dev, pid, ep) != USB_ENDPOINT_XFER_INVALID;
 }
 
 static int is_halted(USBHostDevice *s, int pid, int ep)
@@ -896,7 +906,7 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
 
         urb = &aurb->urb;
         urb->endpoint      = ep;
-        urb->type          = USBDEVFS_URB_TYPE_BULK;
+        urb->type          = usb_host_usbfs_type(s, p);
         urb->usercontext   = s;
         urb->buffer        = pbuf;
         urb->buffer_length = prem;
@@ -992,7 +1002,7 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
 
     trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt);
 
-    for (i = 1; i <= MAX_ENDPOINTS; i++) {
+    for (i = 1; i <= USB_MAX_ENDPOINTS; i++) {
         if (is_isoc(s, USB_TOKEN_IN, i)) {
             usb_host_stop_n_free_iso(s, USB_TOKEN_IN, i);
         }
@@ -1126,10 +1136,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
     int interface, length, i, ep, pid;
     struct endp_data *epd;
 
-    for (i = 0; i < MAX_ENDPOINTS; i++) {
-        s->ep_in[i].type = INVALID_EP_TYPE;
-        s->ep_out[i].type = INVALID_EP_TYPE;
-    }
+    usb_ep_init(&s->dev);
 
     if (s->dev.configuration == 0) {
         /* not configured yet -- leave all endpoints disabled */
@@ -1192,27 +1199,15 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
                 return 1;
             }
 
-            switch (descriptors[i + 3] & 0x3) {
-            case 0x00:
-                type = USBDEVFS_URB_TYPE_CONTROL;
-                break;
-            case 0x01:
-                type = USBDEVFS_URB_TYPE_ISO;
+            type = descriptors[i + 3] & 0x3;
+            if (type == USB_ENDPOINT_XFER_ISOC) {
                 set_max_packet_size(s, pid, ep, descriptors + i);
-                break;
-            case 0x02:
-                type = USBDEVFS_URB_TYPE_BULK;
-                break;
-            case 0x03:
-                type = USBDEVFS_URB_TYPE_INTERRUPT;
-                break;
-            default:
-                DPRINTF("usb_host: malformed endpoint type\n");
-                type = USBDEVFS_URB_TYPE_BULK;
-            }
+            };
+            assert(usb_ep_get_type(&s->dev, pid, ep) ==
+                   USB_ENDPOINT_XFER_INVALID);
+            usb_ep_set_type(&s->dev, pid, ep, type);
+
             epd = get_endp(s, pid, ep);
-            assert(epd->type == INVALID_EP_TYPE);
-            epd->type = type;
             epd->halted = 0;
 
             i += descriptors[i];
@@ -1371,7 +1366,7 @@ static int usb_host_close(USBHostDevice *dev)
 
     qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
     dev->closing = 1;
-    for (i = 1; i <= MAX_ENDPOINTS; i++) {
+    for (i = 1; i <= USB_MAX_ENDPOINTS; i++) {
         if (is_isoc(dev, USB_TOKEN_IN, i)) {
             usb_host_stop_n_free_iso(dev, USB_TOKEN_IN, i);
         }
commit 62c6ae04cf4334ef2ab5ef04581394850f4ea714
Author: Hector Martin <hector at marcansoft.com>
Date:   Sun Feb 27 21:09:09 2011 +0100

    xhci: Initial xHCI implementation
    
    Based on the implementation from Hector Martin <hector at marcansoft.com>
    
    Hectors's implementation completely sidestepped the qemu usb system and
    used libusb directly for usb device pass through.  So I've ripped out
    the libusb bits (or left them in disabled, as reference for further
    coding) and hooked up the qemu subsystem instead.  That work is not
    complete yet though, partly due to limitations of the qemu usb
    subsystem.  Nevertheless I think it is better to continue development
    in-tree, especially as the qemu usb bits need a bunch of improvements
    too for decent usb 3.0 support.
    
    Current state:
      - usb-storage emulation should work ok.
      - Devices which need constant polling (HID emulation like usb-tablet)
        are known to not work.
      - ISO xfers are not implemented yet.
      - superspeed ports are not implemented yet.
      - usb pass-through is completely untested so far.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/Makefile.objs b/Makefile.objs
index 8956cb9..f94c881 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -211,6 +211,7 @@ hw-obj-$(CONFIG_PCKBD) += pckbd.o
 hw-obj-$(CONFIG_USB_UHCI) += usb-uhci.o
 hw-obj-$(CONFIG_USB_OHCI) += usb-ohci.o
 hw-obj-$(CONFIG_USB_EHCI) += usb-ehci.o
+hw-obj-$(CONFIG_USB_XHCI) += usb-xhci.o
 hw-obj-$(CONFIG_FDC) += fdc.o
 hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
 hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o
diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index 22bd350..9d3e1db 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -4,6 +4,7 @@ CONFIG_VIRTIO=y
 CONFIG_USB_UHCI=y
 CONFIG_USB_OHCI=y
 CONFIG_USB_EHCI=y
+CONFIG_USB_XHCI=y
 CONFIG_NE2000_PCI=y
 CONFIG_EEPRO100_PCI=y
 CONFIG_PCNET_PCI=y
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index 83f3893..85e5372 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -120,3 +120,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/usb-xhci.c b/hw/usb-xhci.c
new file mode 100644
index 0000000..28fe9de
--- /dev/null
+++ b/hw/usb-xhci.c
@@ -0,0 +1,2749 @@
+/*
+ * USB xHCI controller emulation
+ *
+ * Copyright (c) 2011 Securiforest
+ * Date: 2011-05-11 ;  Author: Hector Martin <hector at 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 = dev->info->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);
+        dev->info->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 PCIDeviceInfo xhci_info = {
+    .qdev.name    = "nec-usb-xhci",
+    .qdev.alias   = "xhci",
+    .qdev.size    = sizeof(XHCIState),
+    .qdev.vmsd    = &vmstate_xhci,
+    .init         = usb_xhci_initfn,
+    .vendor_id    = PCI_VENDOR_ID_NEC,
+    .device_id    = PCI_DEVICE_ID_NEC_UPD720200,
+    .class_id     = PCI_CLASS_SERIAL_USB,
+    .revision     = 0x03,
+    .is_express   = 1,
+    .config_write = xhci_write_config,
+    .qdev.props   = (Property[]) {
+        DEFINE_PROP_UINT32("msi", XHCIState, msi, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void xhci_register(void)
+{
+    pci_qdev_register(&xhci_info);
+}
+device_init(xhci_register);
commit 8c4ec5c0269bda18bb777a64b2008088d1c632dc
Author: Andrzej Zaborowski <andrew.zaborowski at intel.com>
Date:   Tue Jan 17 02:14:42 2012 +0100

    pxa2xx_keypad: fix unbalanced parenthesis.
    
    Breakage introduced by me when ammending a previous patch, sorry.

diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c
index 0e80212..59db025 100644
--- a/hw/pxa2xx_keypad.c
+++ b/hw/pxa2xx_keypad.c
@@ -165,7 +165,7 @@ static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode)
         kp->kpas |= ((row & 0xf) << 4) | (col & 0xf);
     }
 
-    if (!(kp->kpc & (KPC_AS | KPC_ASACT))
+    if (!(kp->kpc & (KPC_AS | KPC_ASACT)))
         assert_irq = 0;
 
     if (assert_irq && (kp->kpc & KPC_MIE)) {
commit 078758d0741c30d44246383ce5c2ba43281e9aec
Author: Evgeny Voevodin <e.voevodin at samsung.com>
Date:   Fri Jan 13 20:52:40 2012 +0000

    hw/arm_boot.c: Make SMP boards specify address to poll in bootup loop
    
    The secondary CPU bootloader in arm_boot.c holds secondary CPUs in a
    pen until the primary CPU releases them. Make boards specify the
    address to be polled to determine whether to leave the pen (it was
    previously hardcoded to 0x10000030, which is a Versatile Express/
    Realview specific system register address).
    
    Signed-off-by: Evgeny Voevodin <e.voevodin at samsung.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>

diff --git a/hw/arm-misc.h b/hw/arm-misc.h
index af403a1..6e8ae6b 100644
--- a/hw/arm-misc.h
+++ b/hw/arm-misc.h
@@ -31,6 +31,7 @@ struct arm_boot_info {
     const char *initrd_filename;
     target_phys_addr_t loader_start;
     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;
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index 215d5de..bf509a8 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -31,17 +31,17 @@ static uint32_t bootloader[] = {
 /* Entry point for secondary CPUs.  Enable interrupt controller and
    Issue WFI until start address is written to system controller.  */
 static uint32_t smpboot[] = {
-  0xe59f0020, /* ldr     r0, privbase */
-  0xe3a01001, /* mov     r1, #1 */
-  0xe5801100, /* str     r1, [r0, #0x100] */
-  0xe3a00201, /* mov     r0, #0x10000000 */
-  0xe3800030, /* orr     r0, #0x30 */
+  0xe59f201c, /* ldr r2, privbase */
+  0xe59f001c, /* ldr r0, startaddr */
+  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 */
-  0 /* privbase: Private memory region base address.  */
+  0,          /* privbase: Private memory region base address.  */
+  0           /* bootreg: Boot register address is held here */
 };
 
 #define WRITE_WORD(p, value) do { \
@@ -197,6 +197,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;
             }
         }
@@ -272,8 +273,9 @@ 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[10] = info->smp_priv_base;
-            for (n = 0; n < sizeof(smpboot) / 4; 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),
diff --git a/hw/realview.c b/hw/realview.c
index d4191e9..3f35118 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -21,6 +21,7 @@
 #include "exec-memory.h"
 
 #define SMP_BOOT_ADDR 0xe0000000
+#define SMP_BOOTREG_ADDR 0x10000030
 
 typedef struct {
     SysBusDevice busdev;
@@ -96,6 +97,7 @@ static void realview_register_devices(void)
 
 static struct arm_boot_info realview_binfo = {
     .smp_loader_start = SMP_BOOT_ADDR,
+    .smp_bootreg_addr = SMP_BOOTREG_ADDR,
 };
 
 /* The following two lists must be consistent.  */
diff --git a/hw/vexpress.c b/hw/vexpress.c
index 0f39d8d..7111556 100644
--- a/hw/vexpress.c
+++ b/hw/vexpress.c
@@ -31,11 +31,13 @@
 #include "exec-memory.h"
 
 #define SMP_BOOT_ADDR 0xe0000000
+#define SMP_BOOTREG_ADDR 0x10000030
 
 #define VEXPRESS_BOARD_ID 0x8e0
 
 static struct arm_boot_info vexpress_binfo = {
     .smp_loader_start = SMP_BOOT_ADDR,
+    .smp_bootreg_addr = SMP_BOOTREG_ADDR,
 };
 
 static void vexpress_a9_init(ram_addr_t ram_size,
commit ea0e68411e3276060999e2e7db569e3009fc3b81
Author: Evgeny Voevodin <e.voevodin at samsung.com>
Date:   Tue Jan 17 02:08:19 2012 +0100

    hw/sysbus.h: Increase maximum number of device IRQs.
    
    Samsung exynos4210 Interrupt Combiner needs 512 IRQ sources.
    
    Signed-off-by: Evgeny Voevodin <e.voevodin at samsung.com>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>

diff --git a/hw/sysbus.h b/hw/sysbus.h
index 899756b..7b8ca23 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -8,7 +8,7 @@
 
 #define QDEV_MAX_MMIO 32
 #define QDEV_MAX_PIO 32
-#define QDEV_MAX_IRQ 256
+#define QDEV_MAX_IRQ 512
 
 typedef struct SysBusDevice SysBusDevice;
 
commit 753a97c6b40c9ade45aae2e96ed44268aa7007e6
Author: Vasily Khoruzhick <anarsoul at gmail.com>
Date:   Thu Jan 12 22:30:34 2012 +0300

    pxa2xx_keypad: make single automatic scans work
    
    u-boot uses single automatic scans and polling in
    pxa2xx_keypad driver, so clear KPC_AS bit immediately
    and update keys state even if KPC_AS and KPC_ASACT are
    cleared.
    
    Signed-off-by: Vasily Khoruzhick <anarsoul at gmail.com>
    Signed-off-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>

diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c
index a97d445..0e80212 100644
--- a/hw/pxa2xx_keypad.c
+++ b/hw/pxa2xx_keypad.c
@@ -129,48 +129,45 @@ static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode)
     if(!(kp->kpc & KPC_ME)) /* skip if not enabled */
         return;
 
-    if(kp->kpc & KPC_AS || kp->kpc & KPC_ASACT) {
-        if(kp->kpc & KPC_AS)
-            kp->kpc &= ~(KPC_AS);
-
-        rel = (keycode & 0x80) ? 1 : 0; /* key release from qemu */
-        keycode &= ~(0x80); /* strip qemu key release bit */
-        if (kp->alt_code) {
-            keycode |= 0x80;
-            kp->alt_code = 0;
-        }
+    rel = (keycode & 0x80) ? 1 : 0; /* key release from qemu */
+    keycode &= ~0x80; /* strip qemu key release bit */
+    if (kp->alt_code) {
+        keycode |= 0x80;
+        kp->alt_code = 0;
+    }
 
-        row = kp->map[keycode].row;
-        col = kp->map[keycode].column;
-        if(row == -1 || col == -1)
-            return;
+    row = kp->map[keycode].row;
+    col = kp->map[keycode].column;
+    if (row == -1 || col == -1) {
+        return;
+    }
 
-        val = KPASMKPx_MKC(row, col);
-        if (rel) {
-            if (kp->kpasmkp[col / 2] & val) {
-                kp->kpasmkp[col / 2] &= ~val;
-                kp->pressed_cnt--;
-                assert_irq = 1;
-            }
-        } else {
-            if (!(kp->kpasmkp[col / 2] & val)) {
-                kp->kpasmkp[col / 2] |= val;
-                kp->pressed_cnt++;
-                assert_irq = 1;
-            }
+    val = KPASMKPx_MKC(row, col);
+    if (rel) {
+        if (kp->kpasmkp[col / 2] & val) {
+            kp->kpasmkp[col / 2] &= ~val;
+            kp->pressed_cnt--;
+            assert_irq = 1;
         }
-        kp->kpas = ((kp->pressed_cnt & 0x1f) << 26) | (0xf << 4) | 0xf;
-        if (kp->pressed_cnt == 1) {
-            kp->kpas &= ~((0xf << 4) | 0xf);
-            if (rel)
-                pxa27x_keypad_find_pressed_key(kp, &row, &col);
-            kp->kpas |= ((row & 0xf) << 4) | (col & 0xf);
+    } else {
+        if (!(kp->kpasmkp[col / 2] & val)) {
+            kp->kpasmkp[col / 2] |= val;
+            kp->pressed_cnt++;
+            assert_irq = 1;
         }
-        goto out;
     }
-    return;
+    kp->kpas = ((kp->pressed_cnt & 0x1f) << 26) | (0xf << 4) | 0xf;
+    if (kp->pressed_cnt == 1) {
+        kp->kpas &= ~((0xf << 4) | 0xf);
+        if (rel) {
+            pxa27x_keypad_find_pressed_key(kp, &row, &col);
+        }
+        kp->kpas |= ((row & 0xf) << 4) | (col & 0xf);
+    }
+
+    if (!(kp->kpc & (KPC_AS | KPC_ASACT))
+        assert_irq = 0;
 
-out:
     if (assert_irq && (kp->kpc & KPC_MIE)) {
         kp->kpc |= KPC_MI;
         qemu_irq_raise(kp->irq);
@@ -248,6 +245,9 @@ static void pxa2xx_keypad_write(void *opaque, target_phys_addr_t offset,
     switch (offset) {
     case KPC:
         s->kpc = value;
+        if (s->kpc & KPC_AS) {
+            s->kpc &= ~(KPC_AS);
+        }
         break;
     case KPDK:
         s->kpdk = value;
commit 7ab3aedfe3a302f47be1a11be4a63ef5f38de262
Author: Vasily Khoruzhick <anarsoul at gmail.com>
Date:   Thu Jan 12 22:30:35 2012 +0300

    pxa2xx_lcd: fix palette parser
    
    Pallete entry size for 16bpp format is 2 bytes, not 4
    
    Signed-off-by: Vasily Khoruzhick <anarsoul at gmail.com>
    Signed-off-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>

diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c
index 19a09ff..4e9f7b4 100644
--- a/hw/pxa2xx_lcd.c
+++ b/hw/pxa2xx_lcd.c
@@ -577,7 +577,8 @@ static const MemoryRegionOps pxa2xx_lcdc_ops = {
 static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
 {
     int i, n, format, r, g, b, alpha;
-    uint32_t *dest, *src;
+    uint32_t *dest;
+    uint8_t *src;
     s->pal_for = LCCR4_PALFOR(s->control[4]);
     format = s->pal_for;
 
@@ -596,7 +597,7 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
         return;
     }
 
-    src = (uint32_t *) s->dma_ch[ch].pbuffer;
+    src = (uint8_t *) s->dma_ch[ch].pbuffer;
     dest = (uint32_t *) s->dma_ch[ch].palette;
     alpha = r = g = b = 0;
 
@@ -604,43 +605,48 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
         switch (format) {
         case 0: /* 16 bpp, no transparency */
             alpha = 0;
-            if (s->control[0] & LCCR0_CMS)
-                r = g = b = *src & 0xff;
+            if (s->control[0] & LCCR0_CMS) {
+                r = g = b = *(uint16_t *) src & 0xff;
+            }
             else {
-                r = (*src & 0xf800) >> 8;
-                g = (*src & 0x07e0) >> 3;
-                b = (*src & 0x001f) << 3;
+                r = (*(uint16_t *) src & 0xf800) >> 8;
+                g = (*(uint16_t *) src & 0x07e0) >> 3;
+                b = (*(uint16_t *) src & 0x001f) << 3;
             }
+            src += 2;
             break;
         case 1: /* 16 bpp plus transparency */
-            alpha = *src & (1 << 24);
+            alpha = *(uint16_t *) src & (1 << 24);
             if (s->control[0] & LCCR0_CMS)
-                r = g = b = *src & 0xff;
+                r = g = b = *(uint16_t *) src & 0xff;
             else {
-                r = (*src & 0xf800) >> 8;
-                g = (*src & 0x07e0) >> 3;
-                b = (*src & 0x001f) << 3;
+                r = (*(uint16_t *) src & 0xf800) >> 8;
+                g = (*(uint16_t *) src & 0x07e0) >> 3;
+                b = (*(uint16_t *) src & 0x001f) << 3;
             }
+            src += 2;
             break;
         case 2: /* 18 bpp plus transparency */
-            alpha = *src & (1 << 24);
+            alpha = *(uint32_t *) src & (1 << 24);
             if (s->control[0] & LCCR0_CMS)
-                r = g = b = *src & 0xff;
+                r = g = b = *(uint32_t *) src & 0xff;
             else {
-                r = (*src & 0xf80000) >> 16;
-                g = (*src & 0x00fc00) >> 8;
-                b = (*src & 0x0000f8);
+                r = (*(uint32_t *) src & 0xf80000) >> 16;
+                g = (*(uint32_t *) src & 0x00fc00) >> 8;
+                b = (*(uint32_t *) src & 0x0000f8);
             }
+            src += 4;
             break;
         case 3: /* 24 bpp plus transparency */
-            alpha = *src & (1 << 24);
+            alpha = *(uint32_t *) src & (1 << 24);
             if (s->control[0] & LCCR0_CMS)
-                r = g = b = *src & 0xff;
+                r = g = b = *(uint32_t *) src & 0xff;
             else {
-                r = (*src & 0xff0000) >> 16;
-                g = (*src & 0x00ff00) >> 8;
-                b = (*src & 0x0000ff);
+                r = (*(uint32_t *) src & 0xff0000) >> 16;
+                g = (*(uint32_t *) src & 0x00ff00) >> 8;
+                b = (*(uint32_t *) src & 0x0000ff);
             }
+            src += 4;
             break;
         }
         switch (ds_get_bits_per_pixel(s->ds)) {
@@ -660,7 +666,6 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
             *dest = rgb_to_pixel32(r, g, b) | alpha;
             break;
         }
-        src ++;
         dest ++;
     }
 }
commit 41bd360325168b3c1db78eb7311420a1607d521f
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sun Jan 15 17:48:25 2012 +0100

    seabios: Update to release 1.6.3.1
    
    User visible changes in seabios:
     - Probe HPET existence (fix for -no-hpet)
     - Probe PCI existence (fix for -machine isapc)
     - usb: fix boot paths
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin
index bd9ad0e..41e2b38 100644
Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ
diff --git a/roms/seabios b/roms/seabios
index 8e30147..80d11e8 160000
--- a/roms/seabios
+++ b/roms/seabios
@@ -1 +1 @@
-Subproject commit 8e301472e324b6d6496d8b4ffc66863e99d7a505
+Subproject commit 80d11e8577bf03e98f2eb1b0cb3a281ab2879c9e
commit ddcada78895042f1260c6ddd981618e83c52f54f
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Jan 14 14:08:28 2012 +0100

    isapc: Fix segfault during initialization
    
    Obviously, linking the RTC device state to the PIIX does not belong into
    the common path that is shared with the isapc.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index b70431f..3aea3cc 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -201,6 +201,17 @@ static void pc_init1(MemoryRegion *system_memory,
         }
         idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
         idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
+
+        /* FIXME there's some major spaghetti here.  Somehow we create the
+         * devices on the PIIX before we actually create it.  We create the
+         * PIIX3 deep in the recess of the i440fx creation too and then lose
+         * the DeviceState.
+         *
+         * 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);
     } else {
         for(i = 0; i < MAX_IDE_BUS; i++) {
             ISADevice *dev;
@@ -211,17 +222,6 @@ static void pc_init1(MemoryRegion *system_memory,
         }
     }
 
-    /* FIXME there's some major spaghetti here.  Somehow we create the devices
-     * on the PIIX before we actually create it.  We create the PIIX3 deep in
-     * the recess of the i440fx creation too and then lose the DeviceState.
-     *
-     * 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);
-
     audio_init(isa_bus, pci_enabled ? pci_bus : NULL);
 
     pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
commit 3fbffb628c001bd540dc9c1805bdf7aa8591da4d
Author: Avi Kivity <avi at redhat.com>
Date:   Sun Jan 15 16:13:59 2012 +0200

    kvm: flush the dirty log when unregistering a slot
    
    Otherwise, the dirty log information is lost in the kernel forever.
    
    Fixes opensuse-12.1 boot screen, which changes the vga windows rapidly.
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/kvm-all.c b/kvm-all.c
index 3174f42..2cc4562 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -566,6 +566,10 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add)
 
         old = *mem;
 
+        if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) {
+            kvm_physical_sync_dirty_bitmap(section);
+        }
+
         /* unregister the overlapping slot */
         mem->memory_size = 0;
         err = kvm_set_user_memory_region(s, mem);
commit 2be276242135eac6e86be2a8259545e620c94107
Author: Rob Herring <rob.herring at calxeda.com>
Date:   Fri Jan 13 17:25:08 2012 +0000

    arm: Add dummy support for co-processor 15's secure config register
    
    Signed-off-by: Rob Herring <rob.herring at calxeda.com>
    Signed-off-by: Mark Langsdorf <mark.langsdorf at calxeda.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 26b4981..42c53a7 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -116,6 +116,7 @@ typedef struct CPUARMState {
         uint32_t c1_sys; /* System control register.  */
         uint32_t c1_coproc; /* Coprocessor access register.  */
         uint32_t c1_xscaleauxcr; /* XScale auxiliary control register.  */
+        uint32_t c1_scr; /* secure config register.  */
         uint32_t c2_base0; /* MMU translation table base 0.  */
         uint32_t c2_base1; /* MMU translation table base 1.  */
         uint32_t c2_control; /* MMU translation table base control.  */
@@ -452,7 +453,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
 #define cpu_signal_handler cpu_arm_signal_handler
 #define cpu_list arm_cpu_list
 
-#define CPU_SAVE_VERSION 5
+#define CPU_SAVE_VERSION 6
 
 /* MMU modes definitions */
 #define MMU_MODE0_SUFFIX _kernel
diff --git a/target-arm/helper.c b/target-arm/helper.c
index fa42c64..00458fc 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1440,6 +1440,11 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
         }
         goto bad_reg;
     case 1: /* System configuration.  */
+        if (arm_feature(env, ARM_FEATURE_V7)
+                && op1 == 0 && crm == 1 && op2 == 0) {
+            env->cp15.c1_scr = val;
+            break;
+        }
         if (arm_feature(env, ARM_FEATURE_OMAPCP))
             op2 = 0;
         switch (op2) {
@@ -1908,6 +1913,10 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
             goto bad_reg;
         }
     case 1: /* System configuration.  */
+        if (arm_feature(env, ARM_FEATURE_V7)
+            && op1 == 0 && crm == 1 && op2 == 0) {
+            return env->cp15.c1_scr;
+        }
         if (arm_feature(env, ARM_FEATURE_OMAPCP))
             op2 = 0;
         switch (op2) {
diff --git a/target-arm/machine.c b/target-arm/machine.c
index 8984775..f66b8df 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -26,6 +26,7 @@ void cpu_save(QEMUFile *f, void *opaque)
     qemu_put_be32(f, env->cp15.c1_sys);
     qemu_put_be32(f, env->cp15.c1_coproc);
     qemu_put_be32(f, env->cp15.c1_xscaleauxcr);
+    qemu_put_be32(f, env->cp15.c1_scr);
     qemu_put_be32(f, env->cp15.c2_base0);
     qemu_put_be32(f, env->cp15.c2_base1);
     qemu_put_be32(f, env->cp15.c2_control);
@@ -143,6 +144,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     env->cp15.c1_sys = qemu_get_be32(f);
     env->cp15.c1_coproc = qemu_get_be32(f);
     env->cp15.c1_xscaleauxcr = qemu_get_be32(f);
+    env->cp15.c1_scr = qemu_get_be32(f);
     env->cp15.c2_base0 = qemu_get_be32(f);
     env->cp15.c2_base1 = qemu_get_be32(f);
     env->cp15.c2_control = qemu_get_be32(f);
commit d3cb6e2b062f69e0a40f21b74a42f5c5a3422174
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Jan 13 17:25:08 2012 +0000

    target-arm: Fix errors in decode of M profile CPS
    
    Fix errors in the decode of M profile CPS:
     * the decode of the I (affects PRIMASK) and F (affects FAULTMASK)
       bits was reversed
     * the FAULTMASK system register number is 19, not 17
    
    This fixes an issue reported as LP:913925.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/translate.c b/target-arm/translate.c
index f91553a..280bfca 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -9710,15 +9710,15 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
                 break;
             if (IS_M(env)) {
                 tmp = tcg_const_i32((insn & (1 << 4)) != 0);
-                /* PRIMASK */
+                /* FAULTMASK */
                 if (insn & 1) {
-                    addr = tcg_const_i32(16);
+                    addr = tcg_const_i32(19);
                     gen_helper_v7m_msr(cpu_env, addr, tmp);
                     tcg_temp_free_i32(addr);
                 }
-                /* FAULTMASK */
+                /* PRIMASK */
                 if (insn & 2) {
-                    addr = tcg_const_i32(17);
+                    addr = tcg_const_i32(16);
                     gen_helper_v7m_msr(cpu_env, addr, tmp);
                     tcg_temp_free_i32(addr);
                 }
commit 6b620ca3b052e622eef4379cfe37c5c3db5364c9
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Jan 13 17:44:23 2012 +0100

    prepare for future GPLv2+ relicensing
    
    All files under GPLv2 will get GPLv2+ changes starting tomorrow.
    event_notifier.c and exec-obsolete.h were only ever touched by Red Hat
    employees and can be relicensed now.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/aio.c b/aio.c
index 1239ca7..eb3bf42 100644
--- a/aio.c
+++ b/aio.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "qemu-common.h"
diff --git a/block-migration.c b/block-migration.c
index 2b7edbc..4467468 100644
--- a/block-migration.c
+++ b/block-migration.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "qemu-common.h"
diff --git a/block/raw-posix-aio.h b/block/raw-posix-aio.h
index dfc63b8..ba118f6 100644
--- a/block/raw-posix-aio.h
+++ b/block/raw-posix-aio.h
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 #ifndef QEMU_RAW_POSIX_AIO_H
 #define QEMU_RAW_POSIX_AIO_H
diff --git a/block/rbd.c b/block/rbd.c
index 7a2384c..db5abf2 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -7,6 +7,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include <inttypes.h>
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 17a79be..9416400 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -7,6 +7,9 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "qemu-common.h"
diff --git a/buffered_file.c b/buffered_file.c
index fed9a22..f170aa0 100644
--- a/buffered_file.c
+++ b/buffered_file.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "qemu-common.h"
diff --git a/compatfd.c b/compatfd.c
index 02306a4..42f81ca 100644
--- a/compatfd.c
+++ b/compatfd.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "qemu-common.h"
diff --git a/event_notifier.c b/event_notifier.c
index 2c73555..0b82981 100644
--- a/event_notifier.c
+++ b/event_notifier.c
@@ -6,8 +6,8 @@
  * Authors:
  *  Michael S. Tsirkin <mst at redhat.com>
  *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
  */
 
 #include "event_notifier.h"
diff --git a/event_notifier.h b/event_notifier.h
index 24117ea..886222c 100644
--- a/event_notifier.h
+++ b/event_notifier.h
@@ -1,3 +1,15 @@
+/*
+ * event notifier support
+ *
+ * Copyright Red Hat, Inc. 2010
+ *
+ * Authors:
+ *  Michael S. Tsirkin <mst at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
 #ifndef QEMU_EVENT_NOTIFIER_H
 #define QEMU_EVENT_NOTIFIER_H
 
diff --git a/exec-obsolete.h b/exec-obsolete.h
index f8af27e..c412be9 100644
--- a/exec-obsolete.h
+++ b/exec-obsolete.h
@@ -6,8 +6,8 @@
  * Authors:
  *  Avi Kivity <avi at redhat.com>
  *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later.  See the COPYING file in the top-level directory.
  *
  */
 
diff --git a/hmp.c b/hmp.c
index fd4f755..8a77780 100644
--- a/hmp.c
+++ b/hmp.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "hmp.h"
diff --git a/hw/ac97.c b/hw/ac97.c
index 0dbba3b..03be99b 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -12,6 +12,9 @@
  * If you received this file as part of a commercial VirtualBox
  * distribution, then only the terms of your commercial VirtualBox
  * license agreement apply instead of the previous paragraph.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "hw.h"
diff --git a/hw/acpi.c b/hw/acpi.c
index 9c35f2d..79b179b 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -14,6 +14,9 @@
  *
  * 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/>
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 #include "sysemu.h"
 #include "hw.h"
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index d9075e6..bdc55a1 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -14,6 +14,9 @@
  *
  * 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/>
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 #include "hw.h"
 #include "pc.h"
diff --git a/hw/ads7846.c b/hw/ads7846.c
index 9c58a5f..de3f7af 100644
--- a/hw/ads7846.c
+++ b/hw/ads7846.c
@@ -5,6 +5,9 @@
  * Written by Andrzej Zaborowski <balrog at zabor.org>
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "ssi.h"
diff --git a/hw/apm.c b/hw/apm.c
index cdda72f..2aead52 100644
--- a/hw/apm.c
+++ b/hw/apm.c
@@ -15,6 +15,9 @@
  *
  * 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/>
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "apm.h"
diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c
index 18df411..93fb2ed 100644
--- a/hw/bitbang_i2c.c
+++ b/hw/bitbang_i2c.c
@@ -5,6 +5,9 @@
  * Copyright (c) 2008 Jan Kiszka
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 #include "hw.h"
 #include "bitbang_i2c.h"
diff --git a/hw/bonito.c b/hw/bonito.c
index 04d706a..f2c7837 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -5,6 +5,9 @@
  * Copyright (c) 2010 Huacai Chen (zltjiangshi at gmail.com)
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 /*
diff --git a/hw/collie.c b/hw/collie.c
index 8dd6e4e..42f4310 100644
--- a/hw/collie.c
+++ b/hw/collie.c
@@ -4,6 +4,9 @@
  * Copyright (C) 2011 Dmitry Eremin-Solenikov
  *
  * This code is licensed under GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 #include "hw.h"
 #include "sysbus.h"
diff --git a/hw/ds1338.c b/hw/ds1338.c
index 3522af5..f754cb7 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -5,6 +5,9 @@
  * Written by Paul Brook
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "i2c.h"
diff --git a/hw/ecc.c b/hw/ecc.c
index a75408b..60d1f1d 100644
--- a/hw/ecc.c
+++ b/hw/ecc.c
@@ -6,6 +6,9 @@
  * Written by Andrzej Zaborowski <balrog at zabor.org>
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "hw.h"
diff --git a/hw/framebuffer.c b/hw/framebuffer.c
index b43bcdf..6bf48dc 100644
--- a/hw/framebuffer.c
+++ b/hw/framebuffer.c
@@ -5,6 +5,9 @@
  * Written by Paul Brook <paul at codesourcery.com>
  *
  * This code is licensed under the GNU GPLv2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 /* TODO:
diff --git a/hw/gumstix.c b/hw/gumstix.c
index 686a5ed..13a36ea 100644
--- a/hw/gumstix.c
+++ b/hw/gumstix.c
@@ -6,6 +6,9 @@
  * Code based on spitz platform by Andrzej Zaborowski <balrog at zabor.org>
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
  
 /* 
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index 1aa9e3b..bec2e0b 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -12,6 +12,9 @@
  *          Copyright (c) 2006 Igor Kovalenko
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 #include "hw.h"
 #include "pc.h"
diff --git a/hw/kvmclock.c b/hw/kvmclock.c
index 5388bc4..3b9fb20 100644
--- a/hw/kvmclock.c
+++ b/hw/kvmclock.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL version 2.
  * See the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "qemu-common.h"
diff --git a/hw/lan9118.c b/hw/lan9118.c
index 341a521..8b83fe2 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -5,6 +5,9 @@
  * Written by Paul Brook
  *
  * This code is licensed under the GNU GPL v2
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "sysbus.h"
diff --git a/hw/mainstone.c b/hw/mainstone.c
index c914a4e..27f5900 100644
--- a/hw/mainstone.c
+++ b/hw/mainstone.c
@@ -7,6 +7,9 @@
  * Code based on spitz platform by Andrzej Zaborowski <balrog at zabor.org>
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 #include "hw.h"
 #include "pxa.h"
diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c
index 855b792..0cd8410 100644
--- a/hw/marvell_88w8618_audio.c
+++ b/hw/marvell_88w8618_audio.c
@@ -5,6 +5,9 @@
  * Copyright (c) 2008 Jan Kiszka
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 #include "sysbus.h"
 #include "hw.h"
diff --git a/hw/max111x.c b/hw/max111x.c
index 70cd1af..fc79814 100644
--- a/hw/max111x.c
+++ b/hw/max111x.c
@@ -5,6 +5,9 @@
  * Written by Andrzej Zaborowski <balrog at zabor.org>
  *
  * This code is licensed under the GNU GPLv2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "ssi.h"
diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c
index 94ef1df..163a668 100644
--- a/hw/mips_fulong2e.c
+++ b/hw/mips_fulong2e.c
@@ -5,6 +5,9 @@
  * Copyright (c) 2009 chenming (chenming at rdc.faw.com.cn)
  * Copyright (c) 2010 Huacai Chen (zltjiangshi at gmail.com)
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 /*
diff --git a/hw/msix.c b/hw/msix.c
index 149eed2..f47d26b 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -9,6 +9,9 @@
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "hw.h"
diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c
index 9324702..8bfa5dd 100644
--- a/hw/mst_fpga.c
+++ b/hw/mst_fpga.c
@@ -6,6 +6,9 @@
  *                                    <akuster at mvista.com>
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 #include "hw.h"
 #include "sysbus.h"
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 522559d..977ffb6 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -4,6 +4,9 @@
  * Copyright (c) 2008 Jan Kiszka
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "sysbus.h"
diff --git a/hw/nand.c b/hw/nand.c
index 7f25814..8597aa6 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -11,6 +11,9 @@
  * from ST Microelectronics.
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #ifndef NAND_IO
diff --git a/hw/pl031.c b/hw/pl031.c
index a007ff0..2fb0c8e 100644
--- a/hw/pl031.c
+++ b/hw/pl031.c
@@ -7,6 +7,8 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "sysbus.h"
diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c
index f86323f..a97d445 100644
--- a/hw/pxa2xx_keypad.c
+++ b/hw/pxa2xx_keypad.c
@@ -6,6 +6,9 @@
  *              or  <Akuster at mvista.com>
  *
  * This code is licensed under the GPLv2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "hw.h"
diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c
index 5dd4ef0..19a09ff 100644
--- a/hw/pxa2xx_lcd.c
+++ b/hw/pxa2xx_lcd.c
@@ -5,6 +5,9 @@
  * Written by Andrzej Zaborowski <balrog at zabor.org>
  *
  * This code is licensed under the GPLv2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "hw.h"
diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c
index f47c79c..b505a4c 100644
--- a/hw/pxa2xx_mmci.c
+++ b/hw/pxa2xx_mmci.c
@@ -5,6 +5,9 @@
  * Written by Andrzej Zaborowski <balrog at zabor.org>
  *
  * This code is licensed under the GPLv2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "hw.h"
diff --git a/hw/pxa2xx_pcmcia.c b/hw/pxa2xx_pcmcia.c
index dc522dc..b15872a 100644
--- a/hw/pxa2xx_pcmcia.c
+++ b/hw/pxa2xx_pcmcia.c
@@ -5,6 +5,9 @@
  * Written by Andrzej Zaborowski <balrog at zabor.org>
  *
  * This code is licensed under the GPLv2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "hw.h"
diff --git a/hw/smbios.c b/hw/smbios.c
index c9ba43e..c57237d 100644
--- a/hw/smbios.c
+++ b/hw/smbios.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "sysemu.h"
diff --git a/hw/spitz.c b/hw/spitz.c
index 82a133d..9d129c2 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -5,6 +5,9 @@
  * Written by Andrzej Zaborowski <balrog at zabor.org>
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "hw.h"
diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
index 18dabd6..2d89cfe 100644
--- a/hw/ssi-sd.c
+++ b/hw/ssi-sd.c
@@ -5,6 +5,9 @@
  * Written by Paul Brook
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "blockdev.h"
diff --git a/hw/ssi.c b/hw/ssi.c
index 9842fe7..b47953a 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -5,6 +5,9 @@
  * Written by Paul Brook
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "ssi.h"
diff --git a/hw/strongarm.c b/hw/strongarm.c
index 69c1179..fe63fd7 100644
--- a/hw/strongarm.c
+++ b/hw/strongarm.c
@@ -22,6 +22,9 @@
  *
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contributions after 2012-01-13 are licensed under the terms of the
+ *  GNU GPL, version 2 or (at your option) any later version.
  */
 #include "sysbus.h"
 #include "strongarm.h"
diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c
index b75fa60..420925c 100644
--- a/hw/tc6393xb.c
+++ b/hw/tc6393xb.c
@@ -6,6 +6,9 @@
  * Most features are currently unsupported!!!
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 #include "hw.h"
 #include "devices.h"
diff --git a/hw/tosa.c b/hw/tosa.c
index 6bbc6dc..0caba79 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -6,6 +6,9 @@
  *
  * Code based on spitz platform by Andrzej Zaborowski <balrog at zabor.org>
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "hw.h"
diff --git a/hw/vexpress.c b/hw/vexpress.c
index c9ca43c..0f39d8d 100644
--- a/hw/vexpress.c
+++ b/hw/vexpress.c
@@ -16,6 +16,9 @@
  *
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contributions after 2012-01-13 are licensed under the terms of the
+ *  GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "sysbus.h"
diff --git a/hw/vhost.c b/hw/vhost.c
index 19a7b5c..4778521 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -8,6 +8,9 @@
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include <sys/ioctl.h>
diff --git a/hw/vhost_net.c b/hw/vhost_net.c
index 950a6b8..f672e9d 100644
--- a/hw/vhost_net.c
+++ b/hw/vhost_net.c
@@ -8,6 +8,9 @@
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "net.h"
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 77b75bc..caff0aa 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -11,6 +11,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include <inttypes.h>
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 3a9004a..32e46e9 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -13,6 +13,9 @@
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "iov.h"
diff --git a/hw/vt82c686.c b/hw/vt82c686.c
index 038128b..7fb88a5 100644
--- a/hw/vt82c686.c
+++ b/hw/vt82c686.c
@@ -5,6 +5,9 @@
  * Copyright (c) 2009 chenming (chenming at rdc.faw.com.cn)
  * Copyright (c) 2010 Huacai Chen (zltjiangshi at gmail.com)
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "hw.h"
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
index d876cab..2673ace 100644
--- a/hw/xen_backend.c
+++ b/hw/xen_backend.c
@@ -13,6 +13,9 @@
  *
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contributions after 2012-01-13 are licensed under the terms of the
+ *  GNU GPL, version 2 or (at your option) any later version.
  */
 
 /*
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 192e817..68fa36a 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -14,6 +14,9 @@
  *
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contributions after 2012-01-13 are licensed under the terms of the
+ *  GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include <stdio.h>
diff --git a/hw/xen_nic.c b/hw/xen_nic.c
index ef2a2d6..9a59bda 100644
--- a/hw/xen_nic.c
+++ b/hw/xen_nic.c
@@ -14,6 +14,9 @@
  *
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contributions after 2012-01-13 are licensed under the terms of the
+ *  GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include <stdio.h>
diff --git a/hw/z2.c b/hw/z2.c
index a03bb33..8d48488 100644
--- a/hw/z2.c
+++ b/hw/z2.c
@@ -6,6 +6,9 @@
  * Code is based on mainstone platform.
  *
  * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "hw.h"
diff --git a/iov.c b/iov.c
index e7385c4..0f96493 100644
--- a/iov.c
+++ b/iov.c
@@ -10,6 +10,9 @@
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "iov.h"
diff --git a/memory.c b/memory.c
index 5ab2112..6201a37 100644
--- a/memory.c
+++ b/memory.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "memory.h"
diff --git a/migration-exec.c b/migration-exec.c
index e14552e..6c97db9 100644
--- a/migration-exec.c
+++ b/migration-exec.c
@@ -11,6 +11,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "qemu-common.h"
diff --git a/migration-fd.c b/migration-fd.c
index 6211124..5a068c6 100644
--- a/migration-fd.c
+++ b/migration-fd.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "qemu-common.h"
diff --git a/migration-tcp.c b/migration-tcp.c
index cf6a9b8..35a5781 100644
--- a/migration-tcp.c
+++ b/migration-tcp.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "qemu-common.h"
diff --git a/migration-unix.c b/migration-unix.c
index dfcf203..169de88 100644
--- a/migration-unix.c
+++ b/migration-unix.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "qemu-common.h"
diff --git a/migration.c b/migration.c
index 412fdfe..37af438 100644
--- a/migration.c
+++ b/migration.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "qemu-common.h"
diff --git a/module.c b/module.c
index 91f0e61..106a969 100644
--- a/module.c
+++ b/module.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "qemu-common.h"
diff --git a/net/checksum.c b/net/checksum.c
index 4046932..264c23f 100644
--- a/net/checksum.c
+++ b/net/checksum.c
@@ -13,6 +13,9 @@
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Contributions after 2012-01-13 are licensed under the terms of the
+ *  GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "net/checksum.h"
diff --git a/notify.c b/notify.c
index a6bac1f..c104495 100644
--- a/notify.c
+++ b/notify.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "qemu-common.h"
diff --git a/pflib.c b/pflib.c
index 64cb2b3..987e110 100644
--- a/pflib.c
+++ b/pflib.c
@@ -6,6 +6,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 #include "qemu-common.h"
 #include "console.h"
diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index cccb673..d311d13 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include <sys/ioctl.h>
diff --git a/qemu-tool.c b/qemu-tool.c
index 226b6e8..c73bf71 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "qemu-common.h"
diff --git a/qmp.c b/qmp.c
index 5e09b41..c74dde6 100644
--- a/qmp.c
+++ b/qmp.c
@@ -9,6 +9,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "qemu-common.h"
diff --git a/xen-all.c b/xen-all.c
index c86ebf4..d1fc597 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -4,6 +4,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include <sys/mman.h>
diff --git a/xen-mapcache.c b/xen-mapcache.c
index 9fecc64..585b559 100644
--- a/xen-mapcache.c
+++ b/xen-mapcache.c
@@ -4,6 +4,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "config.h"
diff --git a/xen-stub.c b/xen-stub.c
index d403d86..9ea02d4 100644
--- a/xen-stub.c
+++ b/xen-stub.c
@@ -4,6 +4,8 @@
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "qemu-common.h"
commit a10348c3ad3a1bff7c5ace95a32187780d571ebd
Author: Amit Shah <amit.shah at redhat.com>
Date:   Fri Jan 13 15:29:48 2012 +0530

    virtio-console: no need to remove char handlers explicitly
    
    qdev is now equipped (thanks to the last commit) to disassociate
    chardevs from the qdev devices on the devices going away.  So doing it
    in the virtio-console driver is not necessary.
    
    Since that was the only thing being done in the qdev exit method, drop
    it entirely.
    
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index 73d866a..0b28a30 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -125,27 +125,11 @@ static int virtconsole_initfn(VirtIOSerialPort *port)
     return 0;
 }
 
-static int virtconsole_exitfn(VirtIOSerialPort *port)
-{
-    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
-
-    if (vcon->chr) {
-	/*
-	 * Instead of closing the chardev, free it so it can be used
-	 * for other purposes.
-	 */
-	qemu_chr_add_handlers(vcon->chr, NULL, NULL, NULL, NULL);
-    }
-
-    return 0;
-}
-
 static VirtIOSerialPortInfo virtconsole_info = {
     .qdev.name     = "virtconsole",
     .qdev.size     = sizeof(VirtConsole),
     .is_console    = true,
     .init          = virtconsole_initfn,
-    .exit          = virtconsole_exitfn,
     .have_data     = flush_buf,
     .guest_open    = guest_open,
     .guest_close   = guest_close,
@@ -165,7 +149,6 @@ static VirtIOSerialPortInfo virtserialport_info = {
     .qdev.name     = "virtserialport",
     .qdev.size     = sizeof(VirtConsole),
     .init          = virtconsole_initfn,
-    .exit          = virtconsole_exitfn,
     .have_data     = flush_buf,
     .guest_open    = guest_open,
     .guest_close   = guest_close,
commit a87f3e8b080205879232f34ff6977cb225b70e05
Author: Amit Shah <amit.shah at redhat.com>
Date:   Fri Jan 13 15:29:47 2012 +0530

    qdev: Add a 'free' method to disassociate chardev from qdev device
    
    When a device is removed, remove the association with a chardev, if any,
    so that the chardev can be re-used later for other devices.
    
    Reported-by: Qunfang Zhang <qzhang at redhat.com>
    Fix-suggested-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 663c2a0..02f0dae 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -680,6 +680,16 @@ static int parse_chr(DeviceState *dev, Property *prop, const char *str)
     return 0;
 }
 
+static void free_chr(DeviceState *dev, Property *prop)
+{
+    CharDriverState **ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (*ptr) {
+        qemu_chr_add_handlers(*ptr, NULL, NULL, NULL, NULL);
+    }
+}
+
+
 static int print_chr(DeviceState *dev, Property *prop, char *dest, size_t len)
 {
     CharDriverState **ptr = qdev_get_prop_ptr(dev, prop);
@@ -699,6 +709,7 @@ PropertyInfo qdev_prop_chr = {
     .print = print_chr,
     .get   = get_generic,
     .set   = set_generic,
+    .free  = free_chr,
 };
 
 /* --- netdev device --- */
commit 8600361542d64572ad24e04bc25c1ac42000d6d6
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Dec 23 16:17:26 2011 +0100

    vectorize is_dup_page
    
    is_dup_page is already proceeding in 32-bit chunks.  Changing it
    to 16 bytes using Altivec or SSE is easy.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/arch_init.c b/arch_init.c
index 66f7a3f..95ac682 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -95,14 +95,30 @@ const uint32_t arch_type = QEMU_ARCH;
 #define RAM_SAVE_FLAG_EOS      0x10
 #define RAM_SAVE_FLAG_CONTINUE 0x20
 
-static int is_dup_page(uint8_t *page, uint8_t ch)
+#ifdef __ALTIVEC__
+#include <altivec.h>
+#define VECTYPE        vector unsigned char
+#define SPLAT(p)       vec_splat(vec_ld(0, p), 0)
+#define ALL_EQ(v1, v2) vec_all_eq(v1, v2)
+#elif defined __SSE2__
+#include <emmintrin.h>
+#define VECTYPE        __m128i
+#define SPLAT(p)       _mm_set1_epi8(*(p))
+#define ALL_EQ(v1, v2) (_mm_movemask_epi8(_mm_cmpeq_epi8(v1, v2)) == 0xFFFF)
+#else
+#define VECTYPE        unsigned long
+#define SPLAT(p)       (*(p) * (~0UL / 255))
+#define ALL_EQ(v1, v2) ((v1) == (v2))
+#endif
+
+static int is_dup_page(uint8_t *page)
 {
-    uint32_t val = ch << 24 | ch << 16 | ch << 8 | ch;
-    uint32_t *array = (uint32_t *)page;
+    VECTYPE *p = (VECTYPE *)page;
+    VECTYPE val = SPLAT(page);
     int i;
 
-    for (i = 0; i < (TARGET_PAGE_SIZE / 4); i++) {
-        if (array[i] != val) {
+    for (i = 0; i < TARGET_PAGE_SIZE / sizeof(VECTYPE); i++) {
+        if (!ALL_EQ(val, p[i])) {
             return 0;
         }
     }
@@ -134,7 +150,7 @@ static int ram_save_block(QEMUFile *f)
 
             p = memory_region_get_ram_ptr(mr) + offset;
 
-            if (is_dup_page(p, *p)) {
+            if (is_dup_page(p)) {
                 qemu_put_be64(f, offset | cont | RAM_SAVE_FLAG_COMPRESS);
                 if (!cont) {
                     qemu_put_byte(f, strlen(block->idstr));
commit 1ba1f2e319afdcb485963cd3f426fdffd1b725f2
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Dec 23 15:39:03 2011 +0100

    virtio-blk: refuse SG_IO requests with scsi=off
    
    QEMU does have a "scsi" option (to be used like -device
    virtio-blk-pci,drive=foo,scsi=off).  However, it only
    masks the feature bit, and does not reject the command
    if a malicious guest disregards the feature bits and
    issues a request.
    
    Without this patch, using scsi=off does not protect you
    from CVE-2011-4127.
    
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 5e81f53..5b416c3 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -153,6 +153,12 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
     int status;
     int i;
 
+    if ((req->dev->vdev.guest_features & (1 << VIRTIO_BLK_F_SCSI)) == 0) {
+        virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
+        g_free(req);
+        return;
+    }
+
     /*
      * We require at least one output segment each for the virtio_blk_outhdr
      * and the SCSI command block.
commit 701a8f76aa5243d90a71935982c20c06d8e83b80
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Jan 13 17:07:20 2012 +0100

    vmstate: extract declarations out of hw/hw.h
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/hid.h b/hw/hid.h
index 9ce03b1..5315cf7 100644
--- a/hw/hid.h
+++ b/hw/hid.h
@@ -1,6 +1,8 @@
 #ifndef QEMU_HID_H
 #define QEMU_HID_H
 
+#include "vmstate.h"
+
 #define HID_MOUSE     1
 #define HID_TABLET    2
 #define HID_KEYBOARD  3
@@ -56,4 +58,25 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len);
 int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len);
 int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len);
 
+extern const VMStateDescription vmstate_hid_keyboard_device;
+
+#define VMSTATE_HID_KEYBOARD_DEVICE(_field, _state) {                \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(HIDState),                                  \
+    .vmsd       = &vmstate_hid_keyboard_device,                      \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, HIDState),    \
+}
+
+extern const VMStateDescription vmstate_hid_ptr_device;
+
+#define VMSTATE_HID_POINTER_DEVICE(_field, _state) {                 \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(HIDState),                                  \
+    .vmsd       = &vmstate_hid_ptr_device,                           \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, HIDState),    \
+}
+
+
 #endif /* QEMU_HID_H */
diff --git a/hw/hw.h b/hw/hw.h
index 932014a..e5cb9bf 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -10,215 +10,8 @@
 
 #include "ioport.h"
 #include "irq.h"
-
-/* VM Load/Save */
-
-/* This function writes a chunk of data to a file at the given position.
- * The pos argument can be ignored if the file is only being used for
- * streaming.  The handler should try to write all of the data it can.
- */
-typedef int (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf,
-                                    int64_t pos, int size);
-
-/* Read a chunk of data from a file at the given position.  The pos argument
- * can be ignored if the file is only be used for streaming.  The number of
- * bytes actually read should be returned.
- */
-typedef int (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
-                                    int64_t pos, int size);
-
-/* Close a file
- *
- * Return negative error number on error, 0 or positive value on success.
- *
- * The meaning of return value on success depends on the specific back-end being
- * used.
- */
-typedef int (QEMUFileCloseFunc)(void *opaque);
-
-/* Called to determine if the file has exceeded it's bandwidth allocation.  The
- * bandwidth capping is a soft limit, not a hard limit.
- */
-typedef int (QEMUFileRateLimit)(void *opaque);
-
-/* Called to change the current bandwidth allocation. This function must return
- * the new actual bandwidth. It should be new_rate if everything goes ok, and
- * the old rate otherwise
- */
-typedef int64_t (QEMUFileSetRateLimit)(void *opaque, int64_t new_rate);
-typedef int64_t (QEMUFileGetRateLimit)(void *opaque);
-
-QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
-                         QEMUFileGetBufferFunc *get_buffer,
-                         QEMUFileCloseFunc *close,
-                         QEMUFileRateLimit *rate_limit,
-                         QEMUFileSetRateLimit *set_rate_limit,
-			 QEMUFileGetRateLimit *get_rate_limit);
-QEMUFile *qemu_fopen(const char *filename, const char *mode);
-QEMUFile *qemu_fdopen(int fd, const char *mode);
-QEMUFile *qemu_fopen_socket(int fd);
-QEMUFile *qemu_popen(FILE *popen_file, const char *mode);
-QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
-int qemu_stdio_fd(QEMUFile *f);
-void qemu_fflush(QEMUFile *f);
-int qemu_fclose(QEMUFile *f);
-void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size);
-void qemu_put_byte(QEMUFile *f, int v);
-
-static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v)
-{
-    qemu_put_byte(f, (int)v);
-}
-
-#define qemu_put_sbyte qemu_put_byte
-
-void qemu_put_be16(QEMUFile *f, unsigned int v);
-void qemu_put_be32(QEMUFile *f, unsigned int v);
-void qemu_put_be64(QEMUFile *f, uint64_t v);
-int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size);
-int qemu_get_byte(QEMUFile *f);
-
-static inline unsigned int qemu_get_ubyte(QEMUFile *f)
-{
-    return (unsigned int)qemu_get_byte(f);
-}
-
-#define qemu_get_sbyte qemu_get_byte
-
-unsigned int qemu_get_be16(QEMUFile *f);
-unsigned int qemu_get_be32(QEMUFile *f);
-uint64_t qemu_get_be64(QEMUFile *f);
-int qemu_file_rate_limit(QEMUFile *f);
-int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
-int64_t qemu_file_get_rate_limit(QEMUFile *f);
-int qemu_file_get_error(QEMUFile *f);
-void qemu_file_set_error(QEMUFile *f, int error);
-
-/* Try to send any outstanding data.  This function is useful when output is
- * halted due to rate limiting or EAGAIN errors occur as it can be used to
- * resume output. */
-void qemu_file_put_notify(QEMUFile *f);
-
-static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv)
-{
-    qemu_put_be64(f, *pv);
-}
-
-static inline void qemu_put_be32s(QEMUFile *f, const uint32_t *pv)
-{
-    qemu_put_be32(f, *pv);
-}
-
-static inline void qemu_put_be16s(QEMUFile *f, const uint16_t *pv)
-{
-    qemu_put_be16(f, *pv);
-}
-
-static inline void qemu_put_8s(QEMUFile *f, const uint8_t *pv)
-{
-    qemu_put_byte(f, *pv);
-}
-
-static inline void qemu_get_be64s(QEMUFile *f, uint64_t *pv)
-{
-    *pv = qemu_get_be64(f);
-}
-
-static inline void qemu_get_be32s(QEMUFile *f, uint32_t *pv)
-{
-    *pv = qemu_get_be32(f);
-}
-
-static inline void qemu_get_be16s(QEMUFile *f, uint16_t *pv)
-{
-    *pv = qemu_get_be16(f);
-}
-
-static inline void qemu_get_8s(QEMUFile *f, uint8_t *pv)
-{
-    *pv = qemu_get_byte(f);
-}
-
-// Signed versions for type safety
-static inline void qemu_put_sbuffer(QEMUFile *f, const int8_t *buf, int size)
-{
-    qemu_put_buffer(f, (const uint8_t *)buf, size);
-}
-
-static inline void qemu_put_sbe16(QEMUFile *f, int v)
-{
-    qemu_put_be16(f, (unsigned int)v);
-}
-
-static inline void qemu_put_sbe32(QEMUFile *f, int v)
-{
-    qemu_put_be32(f, (unsigned int)v);
-}
-
-static inline void qemu_put_sbe64(QEMUFile *f, int64_t v)
-{
-    qemu_put_be64(f, (uint64_t)v);
-}
-
-static inline size_t qemu_get_sbuffer(QEMUFile *f, int8_t *buf, int size)
-{
-    return qemu_get_buffer(f, (uint8_t *)buf, size);
-}
-
-static inline int qemu_get_sbe16(QEMUFile *f)
-{
-    return (int)qemu_get_be16(f);
-}
-
-static inline int qemu_get_sbe32(QEMUFile *f)
-{
-    return (int)qemu_get_be32(f);
-}
-
-static inline int64_t qemu_get_sbe64(QEMUFile *f)
-{
-    return (int64_t)qemu_get_be64(f);
-}
-
-static inline void qemu_put_s8s(QEMUFile *f, const int8_t *pv)
-{
-    qemu_put_8s(f, (const uint8_t *)pv);
-}
-
-static inline void qemu_put_sbe16s(QEMUFile *f, const int16_t *pv)
-{
-    qemu_put_be16s(f, (const uint16_t *)pv);
-}
-
-static inline void qemu_put_sbe32s(QEMUFile *f, const int32_t *pv)
-{
-    qemu_put_be32s(f, (const uint32_t *)pv);
-}
-
-static inline void qemu_put_sbe64s(QEMUFile *f, const int64_t *pv)
-{
-    qemu_put_be64s(f, (const uint64_t *)pv);
-}
-
-static inline void qemu_get_s8s(QEMUFile *f, int8_t *pv)
-{
-    qemu_get_8s(f, (uint8_t *)pv);
-}
-
-static inline void qemu_get_sbe16s(QEMUFile *f, int16_t *pv)
-{
-    qemu_get_be16s(f, (uint16_t *)pv);
-}
-
-static inline void qemu_get_sbe32s(QEMUFile *f, int32_t *pv)
-{
-    qemu_get_be32s(f, (uint32_t *)pv);
-}
-
-static inline void qemu_get_sbe64s(QEMUFile *f, int64_t *pv)
-{
-    qemu_get_be64s(f, (uint64_t *)pv);
-}
+#include "qemu-file.h"
+#include "vmstate.h"
 
 #ifdef NEED_CPU_H
 #if TARGET_LONG_BITS == 64
@@ -242,37 +35,6 @@ static inline void qemu_get_sbe64s(QEMUFile *f, int64_t *pv)
 #endif
 #endif
 
-int64_t qemu_ftell(QEMUFile *f);
-int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence);
-
-typedef void SaveSetParamsHandler(int blk_enable, int shared, void * opaque);
-typedef void SaveStateHandler(QEMUFile *f, void *opaque);
-typedef int SaveLiveStateHandler(Monitor *mon, QEMUFile *f, int stage,
-                                 void *opaque);
-typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id);
-
-int register_savevm(DeviceState *dev,
-                    const char *idstr,
-                    int instance_id,
-                    int version_id,
-                    SaveStateHandler *save_state,
-                    LoadStateHandler *load_state,
-                    void *opaque);
-
-int register_savevm_live(DeviceState *dev,
-                         const char *idstr,
-                         int instance_id,
-                         int version_id,
-                         SaveSetParamsHandler *set_params,
-			 SaveLiveStateHandler *save_live_state,
-                         SaveStateHandler *save_state,
-                         LoadStateHandler *load_state,
-                         void *opaque);
-
-void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque);
-void register_device_unmigratable(DeviceState *dev, const char *idstr,
-                                                                void *opaque);
-
 typedef void QEMUResetHandler(void *opaque);
 
 void qemu_register_reset(QEMUResetHandler *func, void *opaque);
@@ -284,637 +46,6 @@ typedef int QEMUBootSetHandler(void *opaque, const char *boot_devices);
 void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque);
 int qemu_boot_set(const char *boot_devices);
 
-typedef struct VMStateInfo VMStateInfo;
-typedef struct VMStateDescription VMStateDescription;
-
-struct VMStateInfo {
-    const char *name;
-    int (*get)(QEMUFile *f, void *pv, size_t size);
-    void (*put)(QEMUFile *f, void *pv, size_t size);
-};
-
-enum VMStateFlags {
-    VMS_SINGLE           = 0x001,
-    VMS_POINTER          = 0x002,
-    VMS_ARRAY            = 0x004,
-    VMS_STRUCT           = 0x008,
-    VMS_VARRAY_INT32     = 0x010,  /* Array with size in int32_t field*/
-    VMS_BUFFER           = 0x020,  /* static sized buffer */
-    VMS_ARRAY_OF_POINTER = 0x040,
-    VMS_VARRAY_UINT16    = 0x080,  /* Array with size in uint16_t field */
-    VMS_VBUFFER          = 0x100,  /* Buffer with size in int32_t field */
-    VMS_MULTIPLY         = 0x200,  /* multiply "size" field by field_size */
-    VMS_VARRAY_UINT8     = 0x400,  /* Array with size in uint8_t field*/
-    VMS_VARRAY_UINT32    = 0x800,  /* Array with size in uint32_t field*/
-};
-
-typedef struct {
-    const char *name;
-    size_t offset;
-    size_t size;
-    size_t start;
-    int num;
-    size_t num_offset;
-    size_t size_offset;
-    const VMStateInfo *info;
-    enum VMStateFlags flags;
-    const VMStateDescription *vmsd;
-    int version_id;
-    bool (*field_exists)(void *opaque, int version_id);
-} VMStateField;
-
-typedef struct VMStateSubsection {
-    const VMStateDescription *vmsd;
-    bool (*needed)(void *opaque);
-} VMStateSubsection;
-
-struct VMStateDescription {
-    const char *name;
-    int unmigratable;
-    int version_id;
-    int minimum_version_id;
-    int minimum_version_id_old;
-    LoadStateHandler *load_state_old;
-    int (*pre_load)(void *opaque);
-    int (*post_load)(void *opaque, int version_id);
-    void (*pre_save)(void *opaque);
-    VMStateField *fields;
-    const VMStateSubsection *subsections;
-};
-
-extern const VMStateInfo vmstate_info_bool;
-
-extern const VMStateInfo vmstate_info_int8;
-extern const VMStateInfo vmstate_info_int16;
-extern const VMStateInfo vmstate_info_int32;
-extern const VMStateInfo vmstate_info_int64;
-
-extern const VMStateInfo vmstate_info_uint8_equal;
-extern const VMStateInfo vmstate_info_uint16_equal;
-extern const VMStateInfo vmstate_info_int32_equal;
-extern const VMStateInfo vmstate_info_uint32_equal;
-extern const VMStateInfo vmstate_info_int32_le;
-
-extern const VMStateInfo vmstate_info_uint8;
-extern const VMStateInfo vmstate_info_uint16;
-extern const VMStateInfo vmstate_info_uint32;
-extern const VMStateInfo vmstate_info_uint64;
-
-extern const VMStateInfo vmstate_info_timer;
-extern const VMStateInfo vmstate_info_ptimer;
-extern const VMStateInfo vmstate_info_buffer;
-extern const VMStateInfo vmstate_info_unused_buffer;
-
-#define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)
-#define type_check_pointer(t1,t2) ((t1**)0 - (t2*)0)
-
-#define vmstate_offset_value(_state, _field, _type)                  \
-    (offsetof(_state, _field) +                                      \
-     type_check(_type, typeof_field(_state, _field)))
-
-#define vmstate_offset_pointer(_state, _field, _type)                \
-    (offsetof(_state, _field) +                                      \
-     type_check_pointer(_type, typeof_field(_state, _field)))
-
-#define vmstate_offset_array(_state, _field, _type, _num)            \
-    (offsetof(_state, _field) +                                      \
-     type_check_array(_type, typeof_field(_state, _field), _num))
-
-#define vmstate_offset_sub_array(_state, _field, _type, _start)      \
-    (offsetof(_state, _field[_start]))
-
-#define vmstate_offset_buffer(_state, _field)                        \
-    vmstate_offset_array(_state, _field, uint8_t,                    \
-                         sizeof(typeof_field(_state, _field)))
-
-#define VMSTATE_SINGLE_TEST(_field, _state, _test, _version, _info, _type) { \
-    .name         = (stringify(_field)),                             \
-    .version_id   = (_version),                                      \
-    .field_exists = (_test),                                         \
-    .size         = sizeof(_type),                                   \
-    .info         = &(_info),                                        \
-    .flags        = VMS_SINGLE,                                      \
-    .offset       = vmstate_offset_value(_state, _field, _type),     \
-}
-
-#define VMSTATE_POINTER(_field, _state, _version, _info, _type) {    \
-    .name       = (stringify(_field)),                               \
-    .version_id = (_version),                                        \
-    .info       = &(_info),                                          \
-    .size       = sizeof(_type),                                     \
-    .flags      = VMS_SINGLE|VMS_POINTER,                            \
-    .offset     = vmstate_offset_value(_state, _field, _type),       \
-}
-
-#define VMSTATE_POINTER_TEST(_field, _state, _test, _info, _type) {  \
-    .name       = (stringify(_field)),                               \
-    .info       = &(_info),                                          \
-    .field_exists = (_test),                                         \
-    .size       = sizeof(_type),                                     \
-    .flags      = VMS_SINGLE|VMS_POINTER,                            \
-    .offset     = vmstate_offset_value(_state, _field, _type),       \
-}
-
-#define VMSTATE_ARRAY(_field, _state, _num, _version, _info, _type) {\
-    .name       = (stringify(_field)),                               \
-    .version_id = (_version),                                        \
-    .num        = (_num),                                            \
-    .info       = &(_info),                                          \
-    .size       = sizeof(_type),                                     \
-    .flags      = VMS_ARRAY,                                         \
-    .offset     = vmstate_offset_array(_state, _field, _type, _num), \
-}
-
-#define VMSTATE_ARRAY_TEST(_field, _state, _num, _test, _info, _type) {\
-    .name         = (stringify(_field)),                              \
-    .field_exists = (_test),                                          \
-    .num          = (_num),                                           \
-    .info         = &(_info),                                         \
-    .size         = sizeof(_type),                                    \
-    .flags        = VMS_ARRAY,                                        \
-    .offset       = vmstate_offset_array(_state, _field, _type, _num),\
-}
-
-#define VMSTATE_SUB_ARRAY(_field, _state, _start, _num, _version, _info, _type) { \
-    .name       = (stringify(_field)),                               \
-    .version_id = (_version),                                        \
-    .num        = (_num),                                            \
-    .info       = &(_info),                                          \
-    .size       = sizeof(_type),                                     \
-    .flags      = VMS_ARRAY,                                         \
-    .offset     = vmstate_offset_sub_array(_state, _field, _type, _start), \
-}
-
-#define VMSTATE_ARRAY_INT32_UNSAFE(_field, _state, _field_num, _info, _type) {\
-    .name       = (stringify(_field)),                               \
-    .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
-    .info       = &(_info),                                          \
-    .size       = sizeof(_type),                                     \
-    .flags      = VMS_VARRAY_INT32,                                  \
-    .offset     = offsetof(_state, _field),                          \
-}
-
-#define VMSTATE_VARRAY_INT32(_field, _state, _field_num, _version, _info, _type) {\
-    .name       = (stringify(_field)),                               \
-    .version_id = (_version),                                        \
-    .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
-    .info       = &(_info),                                          \
-    .size       = sizeof(_type),                                     \
-    .flags      = VMS_VARRAY_INT32|VMS_POINTER,                      \
-    .offset     = vmstate_offset_pointer(_state, _field, _type),     \
-}
-
-#define VMSTATE_VARRAY_UINT32(_field, _state, _field_num, _version, _info, _type) {\
-    .name       = (stringify(_field)),                               \
-    .version_id = (_version),                                        \
-    .num_offset = vmstate_offset_value(_state, _field_num, uint32_t),\
-    .info       = &(_info),                                          \
-    .size       = sizeof(_type),                                     \
-    .flags      = VMS_VARRAY_UINT32|VMS_POINTER,                     \
-    .offset     = vmstate_offset_pointer(_state, _field, _type),     \
-}
-
-#define VMSTATE_VARRAY_UINT16_UNSAFE(_field, _state, _field_num, _version, _info, _type) {\
-    .name       = (stringify(_field)),                               \
-    .version_id = (_version),                                        \
-    .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
-    .info       = &(_info),                                          \
-    .size       = sizeof(_type),                                     \
-    .flags      = VMS_VARRAY_UINT16,                                 \
-    .offset     = offsetof(_state, _field),                          \
-}
-
-#define VMSTATE_STRUCT_TEST(_field, _state, _test, _version, _vmsd, _type) { \
-    .name         = (stringify(_field)),                             \
-    .version_id   = (_version),                                      \
-    .field_exists = (_test),                                         \
-    .vmsd         = &(_vmsd),                                        \
-    .size         = sizeof(_type),                                   \
-    .flags        = VMS_STRUCT,                                      \
-    .offset       = vmstate_offset_value(_state, _field, _type),     \
-}
-
-#define VMSTATE_STRUCT_POINTER_TEST(_field, _state, _test, _vmsd, _type) { \
-    .name         = (stringify(_field)),                             \
-    .field_exists = (_test),                                         \
-    .vmsd         = &(_vmsd),                                        \
-    .size         = sizeof(_type),                                   \
-    .flags        = VMS_STRUCT|VMS_POINTER,                          \
-    .offset       = vmstate_offset_value(_state, _field, _type),     \
-}
-
-#define VMSTATE_ARRAY_OF_POINTER(_field, _state, _num, _version, _info, _type) {\
-    .name       = (stringify(_field)),                               \
-    .version_id = (_version),                                        \
-    .num        = (_num),                                            \
-    .info       = &(_info),                                          \
-    .size       = sizeof(_type),                                     \
-    .flags      = VMS_ARRAY|VMS_ARRAY_OF_POINTER,                    \
-    .offset     = vmstate_offset_array(_state, _field, _type, _num), \
-}
-
-#define VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, _test, _version, _vmsd, _type) { \
-    .name         = (stringify(_field)),                             \
-    .num          = (_num),                                          \
-    .field_exists = (_test),                                         \
-    .version_id   = (_version),                                      \
-    .vmsd         = &(_vmsd),                                        \
-    .size         = sizeof(_type),                                   \
-    .flags        = VMS_STRUCT|VMS_ARRAY,                            \
-    .offset       = vmstate_offset_array(_state, _field, _type, _num),\
-}
-
-#define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \
-    .name       = (stringify(_field)),                               \
-    .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \
-    .version_id = (_version),                                        \
-    .vmsd       = &(_vmsd),                                          \
-    .size       = sizeof(_type),                                     \
-    .flags      = VMS_STRUCT|VMS_VARRAY_UINT8,                       \
-    .offset     = offsetof(_state, _field),                          \
-}
-
-#define VMSTATE_STRUCT_VARRAY_POINTER_INT32(_field, _state, _field_num, _vmsd, _type) { \
-    .name       = (stringify(_field)),                               \
-    .version_id = 0,                                                 \
-    .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
-    .size       = sizeof(_type),                                     \
-    .vmsd       = &(_vmsd),                                          \
-    .flags      = VMS_POINTER | VMS_VARRAY_INT32 | VMS_STRUCT,       \
-    .offset     = vmstate_offset_pointer(_state, _field, _type),     \
-}
-
-#define VMSTATE_STRUCT_VARRAY_POINTER_UINT16(_field, _state, _field_num, _vmsd, _type) { \
-    .name       = (stringify(_field)),                               \
-    .version_id = 0,                                                 \
-    .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
-    .size       = sizeof(_type),                                     \
-    .vmsd       = &(_vmsd),                                          \
-    .flags      = VMS_POINTER | VMS_VARRAY_UINT16 | VMS_STRUCT,      \
-    .offset     = vmstate_offset_pointer(_state, _field, _type),     \
-}
-
-#define VMSTATE_STRUCT_VARRAY_INT32(_field, _state, _field_num, _version, _vmsd, _type) { \
-    .name       = (stringify(_field)),                               \
-    .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
-    .version_id = (_version),                                        \
-    .vmsd       = &(_vmsd),                                          \
-    .size       = sizeof(_type),                                     \
-    .flags      = VMS_STRUCT|VMS_VARRAY_INT32,                       \
-    .offset     = offsetof(_state, _field),                          \
-}
-
-#define VMSTATE_STRUCT_VARRAY_UINT32(_field, _state, _field_num, _version, _vmsd, _type) { \
-    .name       = (stringify(_field)),                               \
-    .num_offset = vmstate_offset_value(_state, _field_num, uint32_t), \
-    .version_id = (_version),                                        \
-    .vmsd       = &(_vmsd),                                          \
-    .size       = sizeof(_type),                                     \
-    .flags      = VMS_STRUCT|VMS_VARRAY_UINT32,                      \
-    .offset     = offsetof(_state, _field),                          \
-}
-
-#define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) { \
-    .name         = (stringify(_field)),                             \
-    .version_id   = (_version),                                      \
-    .field_exists = (_test),                                         \
-    .size         = (_size - _start),                                \
-    .info         = &vmstate_info_buffer,                            \
-    .flags        = VMS_BUFFER,                                      \
-    .offset       = vmstate_offset_buffer(_state, _field) + _start,  \
-}
-
-#define VMSTATE_BUFFER_MULTIPLY(_field, _state, _version, _test, _start, _field_size, _multiply) { \
-    .name         = (stringify(_field)),                             \
-    .version_id   = (_version),                                      \
-    .field_exists = (_test),                                         \
-    .size_offset  = vmstate_offset_value(_state, _field_size, uint32_t),\
-    .size         = (_multiply),                                      \
-    .info         = &vmstate_info_buffer,                            \
-    .flags        = VMS_VBUFFER|VMS_MULTIPLY,                        \
-    .offset       = offsetof(_state, _field),                        \
-    .start        = (_start),                                        \
-}
-
-#define VMSTATE_VBUFFER(_field, _state, _version, _test, _start, _field_size) { \
-    .name         = (stringify(_field)),                             \
-    .version_id   = (_version),                                      \
-    .field_exists = (_test),                                         \
-    .size_offset  = vmstate_offset_value(_state, _field_size, int32_t),\
-    .info         = &vmstate_info_buffer,                            \
-    .flags        = VMS_VBUFFER|VMS_POINTER,                         \
-    .offset       = offsetof(_state, _field),                        \
-    .start        = (_start),                                        \
-}
-
-#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _start, _field_size) { \
-    .name         = (stringify(_field)),                             \
-    .version_id   = (_version),                                      \
-    .field_exists = (_test),                                         \
-    .size_offset  = vmstate_offset_value(_state, _field_size, uint32_t),\
-    .info         = &vmstate_info_buffer,                            \
-    .flags        = VMS_VBUFFER|VMS_POINTER,                         \
-    .offset       = offsetof(_state, _field),                        \
-    .start        = (_start),                                        \
-}
-
-#define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) { \
-    .name       = (stringify(_field)),                               \
-    .version_id = (_version),                                        \
-    .size       = (_size),                                           \
-    .info       = &(_info),                                          \
-    .flags      = VMS_BUFFER,                                        \
-    .offset     = offsetof(_state, _field),                          \
-}
-
-#define VMSTATE_UNUSED_BUFFER(_test, _version, _size) {              \
-    .name         = "unused",                                        \
-    .field_exists = (_test),                                         \
-    .version_id   = (_version),                                      \
-    .size         = (_size),                                         \
-    .info         = &vmstate_info_unused_buffer,                     \
-    .flags        = VMS_BUFFER,                                      \
-}
-extern const VMStateDescription vmstate_pci_device;
-
-#define VMSTATE_PCI_DEVICE(_field, _state) {                         \
-    .name       = (stringify(_field)),                               \
-    .size       = sizeof(PCIDevice),                                 \
-    .vmsd       = &vmstate_pci_device,                               \
-    .flags      = VMS_STRUCT,                                        \
-    .offset     = vmstate_offset_value(_state, _field, PCIDevice),   \
-}
-
-#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) {                 \
-    .name       = (stringify(_field)),                               \
-    .size       = sizeof(PCIDevice),                                 \
-    .vmsd       = &vmstate_pci_device,                               \
-    .flags      = VMS_STRUCT|VMS_POINTER,                            \
-    .offset     = vmstate_offset_pointer(_state, _field, PCIDevice), \
-}
-
-extern const VMStateDescription vmstate_pcie_device;
-
-#define VMSTATE_PCIE_DEVICE(_field, _state) {                        \
-    .name       = (stringify(_field)),                               \
-    .version_id = 2,                                                 \
-    .size       = sizeof(PCIDevice),                                 \
-    .vmsd       = &vmstate_pcie_device,                              \
-    .flags      = VMS_STRUCT,                                        \
-    .offset     = vmstate_offset_value(_state, _field, PCIDevice),   \
-}
-
-extern const VMStateDescription vmstate_i2c_slave;
-
-#define VMSTATE_I2C_SLAVE(_field, _state) {                          \
-    .name       = (stringify(_field)),                               \
-    .size       = sizeof(i2c_slave),                                 \
-    .vmsd       = &vmstate_i2c_slave,                                \
-    .flags      = VMS_STRUCT,                                        \
-    .offset     = vmstate_offset_value(_state, _field, i2c_slave),   \
-}
-
-extern const VMStateDescription vmstate_usb_device;
-
-#define VMSTATE_USB_DEVICE(_field, _state) {                         \
-    .name       = (stringify(_field)),                               \
-    .size       = sizeof(USBDevice),                                 \
-    .vmsd       = &vmstate_usb_device,                               \
-    .flags      = VMS_STRUCT,                                        \
-    .offset     = vmstate_offset_value(_state, _field, USBDevice),   \
-}
-
-#define vmstate_offset_macaddr(_state, _field)                       \
-    vmstate_offset_array(_state, _field.a, uint8_t,                \
-                         sizeof(typeof_field(_state, _field)))
-
-#define VMSTATE_MACADDR(_field, _state) {                            \
-    .name       = (stringify(_field)),                               \
-    .size       = sizeof(MACAddr),                                   \
-    .info       = &vmstate_info_buffer,                              \
-    .flags      = VMS_BUFFER,                                        \
-    .offset     = vmstate_offset_macaddr(_state, _field),            \
-}
-
-extern const VMStateDescription vmstate_ptimer;
-
-#define VMSTATE_PTIMER(_field, _state) {                             \
-    .name       = (stringify(_field)),                               \
-    .version_id = (1),                                               \
-    .vmsd       = &vmstate_ptimer,                                   \
-    .size       = sizeof(ptimer_state *),                            \
-    .flags      = VMS_STRUCT|VMS_POINTER,                            \
-    .offset     = vmstate_offset_pointer(_state, _field, ptimer_state), \
-}
-
-extern const VMStateDescription vmstate_hid_keyboard_device;
-
-#define VMSTATE_HID_KEYBOARD_DEVICE(_field, _state) {                \
-    .name       = (stringify(_field)),                               \
-    .size       = sizeof(HIDState),                                  \
-    .vmsd       = &vmstate_hid_keyboard_device,                      \
-    .flags      = VMS_STRUCT,                                        \
-    .offset     = vmstate_offset_value(_state, _field, HIDState),    \
-}
-
-extern const VMStateDescription vmstate_hid_ptr_device;
-
-#define VMSTATE_HID_POINTER_DEVICE(_field, _state) {                 \
-    .name       = (stringify(_field)),                               \
-    .size       = sizeof(HIDState),                                  \
-    .vmsd       = &vmstate_hid_ptr_device,                           \
-    .flags      = VMS_STRUCT,                                        \
-    .offset     = vmstate_offset_value(_state, _field, HIDState),    \
-}
-
-/* _f : field name
-   _f_n : num of elements field_name
-   _n : num of elements
-   _s : struct state name
-   _v : version
-*/
-
-#define VMSTATE_SINGLE(_field, _state, _version, _info, _type)        \
-    VMSTATE_SINGLE_TEST(_field, _state, NULL, _version, _info, _type)
-
-#define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type)        \
-    VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type)
-
-#define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type)          \
-    VMSTATE_STRUCT_POINTER_TEST(_field, _state, NULL, _vmsd, _type)
-
-#define VMSTATE_STRUCT_ARRAY(_field, _state, _num, _version, _vmsd, _type) \
-    VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version,   \
-            _vmsd, _type)
-
-#define VMSTATE_BOOL_V(_f, _s, _v)                                    \
-    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_bool, bool)
-
-#define VMSTATE_INT8_V(_f, _s, _v)                                    \
-    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int8, int8_t)
-#define VMSTATE_INT16_V(_f, _s, _v)                                   \
-    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int16, int16_t)
-#define VMSTATE_INT32_V(_f, _s, _v)                                   \
-    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int32, int32_t)
-#define VMSTATE_INT64_V(_f, _s, _v)                                   \
-    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int64, int64_t)
-
-#define VMSTATE_UINT8_V(_f, _s, _v)                                   \
-    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint8, uint8_t)
-#define VMSTATE_UINT16_V(_f, _s, _v)                                  \
-    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint16, uint16_t)
-#define VMSTATE_UINT32_V(_f, _s, _v)                                  \
-    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint32, uint32_t)
-#define VMSTATE_UINT64_V(_f, _s, _v)                                  \
-    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint64, uint64_t)
-
-#define VMSTATE_BOOL(_f, _s)                                          \
-    VMSTATE_BOOL_V(_f, _s, 0)
-
-#define VMSTATE_INT8(_f, _s)                                          \
-    VMSTATE_INT8_V(_f, _s, 0)
-#define VMSTATE_INT16(_f, _s)                                         \
-    VMSTATE_INT16_V(_f, _s, 0)
-#define VMSTATE_INT32(_f, _s)                                         \
-    VMSTATE_INT32_V(_f, _s, 0)
-#define VMSTATE_INT64(_f, _s)                                         \
-    VMSTATE_INT64_V(_f, _s, 0)
-
-#define VMSTATE_UINT8(_f, _s)                                         \
-    VMSTATE_UINT8_V(_f, _s, 0)
-#define VMSTATE_UINT16(_f, _s)                                        \
-    VMSTATE_UINT16_V(_f, _s, 0)
-#define VMSTATE_UINT32(_f, _s)                                        \
-    VMSTATE_UINT32_V(_f, _s, 0)
-#define VMSTATE_UINT64(_f, _s)                                        \
-    VMSTATE_UINT64_V(_f, _s, 0)
-
-#define VMSTATE_UINT8_EQUAL(_f, _s)                                   \
-    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint8_equal, uint8_t)
-
-#define VMSTATE_UINT16_EQUAL(_f, _s)                                  \
-    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint16_equal, uint16_t)
-
-#define VMSTATE_UINT16_EQUAL_V(_f, _s, _v)                            \
-    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint16_equal, uint16_t)
-
-#define VMSTATE_INT32_EQUAL(_f, _s)                                   \
-    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_equal, int32_t)
-
-#define VMSTATE_UINT32_EQUAL(_f, _s)                                   \
-    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint32_equal, uint32_t)
-
-#define VMSTATE_INT32_LE(_f, _s)                                   \
-    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
-
-#define VMSTATE_UINT8_TEST(_f, _s, _t)                               \
-    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint8, uint8_t)
-
-#define VMSTATE_UINT16_TEST(_f, _s, _t)                               \
-    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint16, uint16_t)
-
-#define VMSTATE_UINT32_TEST(_f, _s, _t)                                  \
-    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint32, uint32_t)
-
-#define VMSTATE_TIMER_TEST(_f, _s, _test)                             \
-    VMSTATE_POINTER_TEST(_f, _s, _test, vmstate_info_timer, QEMUTimer *)
-
-#define VMSTATE_TIMER(_f, _s)                                         \
-    VMSTATE_TIMER_TEST(_f, _s, NULL)
-
-#define VMSTATE_TIMER_ARRAY(_f, _s, _n)                              \
-    VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *)
-
-#define VMSTATE_BOOL_ARRAY_V(_f, _s, _n, _v)                         \
-    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_bool, bool)
-
-#define VMSTATE_BOOL_ARRAY(_f, _s, _n)                               \
-    VMSTATE_BOOL_ARRAY_V(_f, _s, _n, 0)
-
-#define VMSTATE_UINT16_ARRAY_V(_f, _s, _n, _v)                         \
-    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint16, uint16_t)
-
-#define VMSTATE_UINT16_ARRAY(_f, _s, _n)                               \
-    VMSTATE_UINT16_ARRAY_V(_f, _s, _n, 0)
-
-#define VMSTATE_UINT8_ARRAY_V(_f, _s, _n, _v)                         \
-    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint8, uint8_t)
-
-#define VMSTATE_UINT8_ARRAY(_f, _s, _n)                               \
-    VMSTATE_UINT8_ARRAY_V(_f, _s, _n, 0)
-
-#define VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v)                        \
-    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint32, uint32_t)
-
-#define VMSTATE_UINT32_ARRAY(_f, _s, _n)                              \
-    VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0)
-
-#define VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v)                        \
-    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint64, uint64_t)
-
-#define VMSTATE_UINT64_ARRAY(_f, _s, _n)                              \
-    VMSTATE_UINT64_ARRAY_V(_f, _s, _n, 0)
-
-#define VMSTATE_INT16_ARRAY_V(_f, _s, _n, _v)                         \
-    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int16, int16_t)
-
-#define VMSTATE_INT16_ARRAY(_f, _s, _n)                               \
-    VMSTATE_INT16_ARRAY_V(_f, _s, _n, 0)
-
-#define VMSTATE_INT32_ARRAY_V(_f, _s, _n, _v)                         \
-    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int32, int32_t)
-
-#define VMSTATE_INT32_ARRAY(_f, _s, _n)                               \
-    VMSTATE_INT32_ARRAY_V(_f, _s, _n, 0)
-
-#define VMSTATE_UINT32_SUB_ARRAY(_f, _s, _start, _num)                \
-    VMSTATE_SUB_ARRAY(_f, _s, _start, _num, 0, vmstate_info_uint32, uint32_t)
-
-#define VMSTATE_UINT32_ARRAY(_f, _s, _n)                              \
-    VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0)
-
-#define VMSTATE_INT64_ARRAY_V(_f, _s, _n, _v)                         \
-    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int64, int64_t)
-
-#define VMSTATE_INT64_ARRAY(_f, _s, _n)                               \
-    VMSTATE_INT64_ARRAY_V(_f, _s, _n, 0)
-
-#define VMSTATE_BUFFER_V(_f, _s, _v)                                  \
-    VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, 0, sizeof(typeof_field(_s, _f)))
-
-#define VMSTATE_BUFFER(_f, _s)                                        \
-    VMSTATE_BUFFER_V(_f, _s, 0)
-
-#define VMSTATE_PARTIAL_BUFFER(_f, _s, _size)                         \
-    VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, 0, _size)
-
-#define VMSTATE_BUFFER_START_MIDDLE(_f, _s, _start) \
-    VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, _start, sizeof(typeof_field(_s, _f)))
-
-#define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size)                        \
-    VMSTATE_VBUFFER(_f, _s, 0, NULL, 0, _size)
-
-#define VMSTATE_PARTIAL_VBUFFER_UINT32(_f, _s, _size)                        \
-    VMSTATE_VBUFFER_UINT32(_f, _s, 0, NULL, 0, _size)
-
-#define VMSTATE_SUB_VBUFFER(_f, _s, _start, _size)                    \
-    VMSTATE_VBUFFER(_f, _s, 0, NULL, _start, _size)
-
-#define VMSTATE_BUFFER_TEST(_f, _s, _test)                            \
-    VMSTATE_STATIC_BUFFER(_f, _s, 0, _test, 0, sizeof(typeof_field(_s, _f)))
-
-#define VMSTATE_BUFFER_UNSAFE(_field, _state, _version, _size)        \
-    VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, vmstate_info_buffer, _size)
-
-#define VMSTATE_UNUSED_V(_v, _size)                                   \
-    VMSTATE_UNUSED_BUFFER(NULL, _v, _size)
-
-#define VMSTATE_UNUSED(_size)                                         \
-    VMSTATE_UNUSED_V(0, _size)
-
-#define VMSTATE_UNUSED_TEST(_test, _size)                             \
-    VMSTATE_UNUSED_BUFFER(_test, 0, _size)
-
 #ifdef NEED_CPU_H
 #if TARGET_LONG_BITS == 64
 #define VMSTATE_UINTTL_V(_f, _s, _v)                                  \
@@ -934,24 +65,4 @@ extern const VMStateDescription vmstate_hid_ptr_device;
 
 #endif
 
-#define VMSTATE_END_OF_LIST()                                         \
-    {}
-
-int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
-                       void *opaque, int version_id);
-void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
-                        void *opaque);
-int vmstate_register(DeviceState *dev, int instance_id,
-                     const VMStateDescription *vmsd, void *base);
-int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
-                                   const VMStateDescription *vmsd,
-                                   void *base, int alias_id,
-                                   int required_for_version);
-void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
-                        void *opaque);
-struct MemoryRegion;
-void vmstate_register_ram(struct MemoryRegion *memory, DeviceState *dev);
-void vmstate_unregister_ram(struct MemoryRegion *memory, DeviceState *dev);
-void vmstate_register_ram_global(struct MemoryRegion *memory);
-
 #endif
diff --git a/hw/i2c.h b/hw/i2c.h
index 9381d01..a3383ff 100644
--- a/hw/i2c.h
+++ b/hw/i2c.h
@@ -74,4 +74,14 @@ void tmp105_set(i2c_slave *i2c, int temp);
 /* lm832x.c */
 void lm832x_key_event(DeviceState *dev, int key, int state);
 
+extern const VMStateDescription vmstate_i2c_slave;
+
+#define VMSTATE_I2C_SLAVE(_field, _state) {                          \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(i2c_slave),                                 \
+    .vmsd       = &vmstate_i2c_slave,                                \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, i2c_slave),   \
+}
+
 #endif
diff --git a/hw/pci.h b/hw/pci.h
index 625e717..0d2cff6 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -552,4 +552,22 @@ static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev,
     qemu_sglist_init(qsg, alloc_hint);
 }
 
+extern const VMStateDescription vmstate_pci_device;
+
+#define VMSTATE_PCI_DEVICE(_field, _state) {                         \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(PCIDevice),                                 \
+    .vmsd       = &vmstate_pci_device,                               \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, PCIDevice),   \
+}
+
+#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) {                 \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(PCIDevice),                                 \
+    .vmsd       = &vmstate_pci_device,                               \
+    .flags      = VMS_STRUCT|VMS_POINTER,                            \
+    .offset     = vmstate_offset_pointer(_state, _field, PCIDevice), \
+}
+
 #endif
diff --git a/hw/pcie.h b/hw/pcie.h
index a213fba..b8ab0c7 100644
--- a/hw/pcie.h
+++ b/hw/pcie.h
@@ -129,4 +129,15 @@ void pcie_add_capability(PCIDevice *dev,
 
 void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn);
 
+extern const VMStateDescription vmstate_pcie_device;
+
+#define VMSTATE_PCIE_DEVICE(_field, _state) {                        \
+    .name       = (stringify(_field)),                               \
+    .version_id = 2,                                                 \
+    .size       = sizeof(PCIDevice),                                 \
+    .vmsd       = &vmstate_pcie_device,                              \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, PCIDevice),   \
+}
+
 #endif /* QEMU_PCIE_H */
diff --git a/hw/ptimer.h b/hw/ptimer.h
index 69cdddc..6638f61 100644
--- a/hw/ptimer.h
+++ b/hw/ptimer.h
@@ -10,6 +10,7 @@
 
 #include "qemu-common.h"
 #include "qemu-timer.h"
+#include "vmstate.h"
 
 /* ptimer.c */
 typedef struct ptimer_state ptimer_state;
@@ -24,4 +25,15 @@ void ptimer_set_count(ptimer_state *s, uint64_t count);
 void ptimer_run(ptimer_state *s, int oneshot);
 void ptimer_stop(ptimer_state *s);
 
+extern const VMStateDescription vmstate_ptimer;
+
+#define VMSTATE_PTIMER(_field, _state) {                             \
+    .name       = (stringify(_field)),                               \
+    .version_id = (1),                                               \
+    .vmsd       = &vmstate_ptimer,                                   \
+    .size       = sizeof(ptimer_state *),                            \
+    .flags      = VMS_STRUCT|VMS_POINTER,                            \
+    .offset     = vmstate_offset_pointer(_state, _field, ptimer_state), \
+}
+
 #endif
diff --git a/hw/usb.h b/hw/usb.h
index c6e1870..7ea90e4 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -392,3 +392,15 @@ static inline USBBus *usb_bus_from_device(USBDevice *d)
 {
     return DO_UPCAST(USBBus, qbus, d->qdev.parent_bus);
 }
+
+extern const VMStateDescription vmstate_usb_device;
+
+#define VMSTATE_USB_DEVICE(_field, _state) {                         \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(USBDevice),                                 \
+    .vmsd       = &vmstate_usb_device,                               \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, USBDevice),   \
+}
+
+
diff --git a/net.h b/net.h
index c6b4190..eab089d 100644
--- a/net.h
+++ b/net.h
@@ -6,6 +6,7 @@
 #include "qdict.h"
 #include "qemu-option.h"
 #include "net/queue.h"
+#include "vmstate.h"
 
 struct MACAddr {
     uint8_t a[6];
@@ -178,4 +179,16 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd);
 
 int net_handle_fd_param(Monitor *mon, const char *param);
 
+#define vmstate_offset_macaddr(_state, _field)                       \
+    vmstate_offset_array(_state, _field.a, uint8_t,                \
+                         sizeof(typeof_field(_state, _field)))
+
+#define VMSTATE_MACADDR(_field, _state) {                            \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(MACAddr),                                   \
+    .info       = &vmstate_info_buffer,                              \
+    .flags      = VMS_BUFFER,                                        \
+    .offset     = vmstate_offset_macaddr(_state, _field),            \
+}
+
 #endif
diff --git a/qemu-file.h b/qemu-file.h
new file mode 100644
index 0000000..8da1021
--- /dev/null
+++ b/qemu-file.h
@@ -0,0 +1,238 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 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.
+ */
+#ifndef QEMU_FILE_H
+#define QEMU_FILE_H 1
+
+/* This function writes a chunk of data to a file at the given position.
+ * The pos argument can be ignored if the file is only being used for
+ * streaming.  The handler should try to write all of the data it can.
+ */
+typedef int (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf,
+                                    int64_t pos, int size);
+
+/* Read a chunk of data from a file at the given position.  The pos argument
+ * can be ignored if the file is only be used for streaming.  The number of
+ * bytes actually read should be returned.
+ */
+typedef int (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
+                                    int64_t pos, int size);
+
+/* Close a file
+ *
+ * Return negative error number on error, 0 or positive value on success.
+ *
+ * The meaning of return value on success depends on the specific back-end being
+ * used.
+ */
+typedef int (QEMUFileCloseFunc)(void *opaque);
+
+/* Called to determine if the file has exceeded it's bandwidth allocation.  The
+ * bandwidth capping is a soft limit, not a hard limit.
+ */
+typedef int (QEMUFileRateLimit)(void *opaque);
+
+/* Called to change the current bandwidth allocation. This function must return
+ * the new actual bandwidth. It should be new_rate if everything goes ok, and
+ * the old rate otherwise
+ */
+typedef int64_t (QEMUFileSetRateLimit)(void *opaque, int64_t new_rate);
+typedef int64_t (QEMUFileGetRateLimit)(void *opaque);
+
+QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
+                         QEMUFileGetBufferFunc *get_buffer,
+                         QEMUFileCloseFunc *close,
+                         QEMUFileRateLimit *rate_limit,
+                         QEMUFileSetRateLimit *set_rate_limit,
+                         QEMUFileGetRateLimit *get_rate_limit);
+QEMUFile *qemu_fopen(const char *filename, const char *mode);
+QEMUFile *qemu_fdopen(int fd, const char *mode);
+QEMUFile *qemu_fopen_socket(int fd);
+QEMUFile *qemu_popen(FILE *popen_file, const char *mode);
+QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
+int qemu_stdio_fd(QEMUFile *f);
+void qemu_fflush(QEMUFile *f);
+int qemu_fclose(QEMUFile *f);
+void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size);
+void qemu_put_byte(QEMUFile *f, int v);
+
+static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v)
+{
+    qemu_put_byte(f, (int)v);
+}
+
+#define qemu_put_sbyte qemu_put_byte
+
+void qemu_put_be16(QEMUFile *f, unsigned int v);
+void qemu_put_be32(QEMUFile *f, unsigned int v);
+void qemu_put_be64(QEMUFile *f, uint64_t v);
+int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size);
+int qemu_get_byte(QEMUFile *f);
+
+static inline unsigned int qemu_get_ubyte(QEMUFile *f)
+{
+    return (unsigned int)qemu_get_byte(f);
+}
+
+#define qemu_get_sbyte qemu_get_byte
+
+unsigned int qemu_get_be16(QEMUFile *f);
+unsigned int qemu_get_be32(QEMUFile *f);
+uint64_t qemu_get_be64(QEMUFile *f);
+
+int qemu_file_rate_limit(QEMUFile *f);
+int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
+int64_t qemu_file_get_rate_limit(QEMUFile *f);
+int qemu_file_get_error(QEMUFile *f);
+void qemu_file_set_error(QEMUFile *f, int error);
+
+/* Try to send any outstanding data.  This function is useful when output is
+ * halted due to rate limiting or EAGAIN errors occur as it can be used to
+ * resume output. */
+void qemu_file_put_notify(QEMUFile *f);
+
+static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv)
+{
+    qemu_put_be64(f, *pv);
+}
+
+static inline void qemu_put_be32s(QEMUFile *f, const uint32_t *pv)
+{
+    qemu_put_be32(f, *pv);
+}
+
+static inline void qemu_put_be16s(QEMUFile *f, const uint16_t *pv)
+{
+    qemu_put_be16(f, *pv);
+}
+
+static inline void qemu_put_8s(QEMUFile *f, const uint8_t *pv)
+{
+    qemu_put_byte(f, *pv);
+}
+
+static inline void qemu_get_be64s(QEMUFile *f, uint64_t *pv)
+{
+    *pv = qemu_get_be64(f);
+}
+
+static inline void qemu_get_be32s(QEMUFile *f, uint32_t *pv)
+{
+    *pv = qemu_get_be32(f);
+}
+
+static inline void qemu_get_be16s(QEMUFile *f, uint16_t *pv)
+{
+    *pv = qemu_get_be16(f);
+}
+
+static inline void qemu_get_8s(QEMUFile *f, uint8_t *pv)
+{
+    *pv = qemu_get_byte(f);
+}
+
+// Signed versions for type safety
+static inline void qemu_put_sbuffer(QEMUFile *f, const int8_t *buf, int size)
+{
+    qemu_put_buffer(f, (const uint8_t *)buf, size);
+}
+
+static inline void qemu_put_sbe16(QEMUFile *f, int v)
+{
+    qemu_put_be16(f, (unsigned int)v);
+}
+
+static inline void qemu_put_sbe32(QEMUFile *f, int v)
+{
+    qemu_put_be32(f, (unsigned int)v);
+}
+
+static inline void qemu_put_sbe64(QEMUFile *f, int64_t v)
+{
+    qemu_put_be64(f, (uint64_t)v);
+}
+
+static inline size_t qemu_get_sbuffer(QEMUFile *f, int8_t *buf, int size)
+{
+    return qemu_get_buffer(f, (uint8_t *)buf, size);
+}
+
+static inline int qemu_get_sbe16(QEMUFile *f)
+{
+    return (int)qemu_get_be16(f);
+}
+
+static inline int qemu_get_sbe32(QEMUFile *f)
+{
+    return (int)qemu_get_be32(f);
+}
+
+static inline int64_t qemu_get_sbe64(QEMUFile *f)
+{
+    return (int64_t)qemu_get_be64(f);
+}
+
+static inline void qemu_put_s8s(QEMUFile *f, const int8_t *pv)
+{
+    qemu_put_8s(f, (const uint8_t *)pv);
+}
+
+static inline void qemu_put_sbe16s(QEMUFile *f, const int16_t *pv)
+{
+    qemu_put_be16s(f, (const uint16_t *)pv);
+}
+
+static inline void qemu_put_sbe32s(QEMUFile *f, const int32_t *pv)
+{
+    qemu_put_be32s(f, (const uint32_t *)pv);
+}
+
+static inline void qemu_put_sbe64s(QEMUFile *f, const int64_t *pv)
+{
+    qemu_put_be64s(f, (const uint64_t *)pv);
+}
+
+static inline void qemu_get_s8s(QEMUFile *f, int8_t *pv)
+{
+    qemu_get_8s(f, (uint8_t *)pv);
+}
+
+static inline void qemu_get_sbe16s(QEMUFile *f, int16_t *pv)
+{
+    qemu_get_be16s(f, (uint16_t *)pv);
+}
+
+static inline void qemu_get_sbe32s(QEMUFile *f, int32_t *pv)
+{
+    qemu_get_be32s(f, (uint32_t *)pv);
+}
+
+static inline void qemu_get_sbe64s(QEMUFile *f, int64_t *pv)
+{
+    qemu_get_be64s(f, (uint64_t *)pv);
+}
+
+int64_t qemu_ftell(QEMUFile *f);
+int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence);
+
+#endif
diff --git a/vmstate.h b/vmstate.h
new file mode 100644
index 0000000..9d3c49c
--- /dev/null
+++ b/vmstate.h
@@ -0,0 +1,618 @@
+/*
+ * QEMU migration/snapshot declarations
+ *
+ * Copyright (c) 2009-2011 Red Hat, Inc.
+ *
+ * Original author: Juan Quintela <quintela at redhat.com>
+ *
+ * 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_VMSTATE_H
+#define QEMU_VMSTATE_H 1
+
+typedef void SaveSetParamsHandler(int blk_enable, int shared, void * opaque);
+typedef void SaveStateHandler(QEMUFile *f, void *opaque);
+typedef int SaveLiveStateHandler(Monitor *mon, QEMUFile *f, int stage,
+                                 void *opaque);
+typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id);
+
+int register_savevm(DeviceState *dev,
+                    const char *idstr,
+                    int instance_id,
+                    int version_id,
+                    SaveStateHandler *save_state,
+                    LoadStateHandler *load_state,
+                    void *opaque);
+
+int register_savevm_live(DeviceState *dev,
+                         const char *idstr,
+                         int instance_id,
+                         int version_id,
+                         SaveSetParamsHandler *set_params,
+                         SaveLiveStateHandler *save_live_state,
+                         SaveStateHandler *save_state,
+                         LoadStateHandler *load_state,
+                         void *opaque);
+
+void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque);
+void register_device_unmigratable(DeviceState *dev, const char *idstr,
+                                                                void *opaque);
+
+
+typedef struct VMStateInfo VMStateInfo;
+typedef struct VMStateDescription VMStateDescription;
+
+struct VMStateInfo {
+    const char *name;
+    int (*get)(QEMUFile *f, void *pv, size_t size);
+    void (*put)(QEMUFile *f, void *pv, size_t size);
+};
+
+enum VMStateFlags {
+    VMS_SINGLE           = 0x001,
+    VMS_POINTER          = 0x002,
+    VMS_ARRAY            = 0x004,
+    VMS_STRUCT           = 0x008,
+    VMS_VARRAY_INT32     = 0x010,  /* Array with size in int32_t field*/
+    VMS_BUFFER           = 0x020,  /* static sized buffer */
+    VMS_ARRAY_OF_POINTER = 0x040,
+    VMS_VARRAY_UINT16    = 0x080,  /* Array with size in uint16_t field */
+    VMS_VBUFFER          = 0x100,  /* Buffer with size in int32_t field */
+    VMS_MULTIPLY         = 0x200,  /* multiply "size" field by field_size */
+    VMS_VARRAY_UINT8     = 0x400,  /* Array with size in uint8_t field*/
+    VMS_VARRAY_UINT32    = 0x800,  /* Array with size in uint32_t field*/
+};
+
+typedef struct {
+    const char *name;
+    size_t offset;
+    size_t size;
+    size_t start;
+    int num;
+    size_t num_offset;
+    size_t size_offset;
+    const VMStateInfo *info;
+    enum VMStateFlags flags;
+    const VMStateDescription *vmsd;
+    int version_id;
+    bool (*field_exists)(void *opaque, int version_id);
+} VMStateField;
+
+typedef struct VMStateSubsection {
+    const VMStateDescription *vmsd;
+    bool (*needed)(void *opaque);
+} VMStateSubsection;
+
+struct VMStateDescription {
+    const char *name;
+    int unmigratable;
+    int version_id;
+    int minimum_version_id;
+    int minimum_version_id_old;
+    LoadStateHandler *load_state_old;
+    int (*pre_load)(void *opaque);
+    int (*post_load)(void *opaque, int version_id);
+    void (*pre_save)(void *opaque);
+    VMStateField *fields;
+    const VMStateSubsection *subsections;
+};
+
+extern const VMStateInfo vmstate_info_bool;
+
+extern const VMStateInfo vmstate_info_int8;
+extern const VMStateInfo vmstate_info_int16;
+extern const VMStateInfo vmstate_info_int32;
+extern const VMStateInfo vmstate_info_int64;
+
+extern const VMStateInfo vmstate_info_uint8_equal;
+extern const VMStateInfo vmstate_info_uint16_equal;
+extern const VMStateInfo vmstate_info_int32_equal;
+extern const VMStateInfo vmstate_info_uint32_equal;
+extern const VMStateInfo vmstate_info_int32_le;
+
+extern const VMStateInfo vmstate_info_uint8;
+extern const VMStateInfo vmstate_info_uint16;
+extern const VMStateInfo vmstate_info_uint32;
+extern const VMStateInfo vmstate_info_uint64;
+
+extern const VMStateInfo vmstate_info_timer;
+extern const VMStateInfo vmstate_info_buffer;
+extern const VMStateInfo vmstate_info_unused_buffer;
+
+#define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)
+#define type_check_pointer(t1,t2) ((t1**)0 - (t2*)0)
+
+#define vmstate_offset_value(_state, _field, _type)                  \
+    (offsetof(_state, _field) +                                      \
+     type_check(_type, typeof_field(_state, _field)))
+
+#define vmstate_offset_pointer(_state, _field, _type)                \
+    (offsetof(_state, _field) +                                      \
+     type_check_pointer(_type, typeof_field(_state, _field)))
+
+#define vmstate_offset_array(_state, _field, _type, _num)            \
+    (offsetof(_state, _field) +                                      \
+     type_check_array(_type, typeof_field(_state, _field), _num))
+
+#define vmstate_offset_sub_array(_state, _field, _type, _start)      \
+    (offsetof(_state, _field[_start]))
+
+#define vmstate_offset_buffer(_state, _field)                        \
+    vmstate_offset_array(_state, _field, uint8_t,                    \
+                         sizeof(typeof_field(_state, _field)))
+
+#define VMSTATE_SINGLE_TEST(_field, _state, _test, _version, _info, _type) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .size         = sizeof(_type),                                   \
+    .info         = &(_info),                                        \
+    .flags        = VMS_SINGLE,                                      \
+    .offset       = vmstate_offset_value(_state, _field, _type),     \
+}
+
+#define VMSTATE_POINTER(_field, _state, _version, _info, _type) {    \
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_SINGLE|VMS_POINTER,                            \
+    .offset     = vmstate_offset_value(_state, _field, _type),       \
+}
+
+#define VMSTATE_POINTER_TEST(_field, _state, _test, _info, _type) {  \
+    .name       = (stringify(_field)),                               \
+    .info       = &(_info),                                          \
+    .field_exists = (_test),                                         \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_SINGLE|VMS_POINTER,                            \
+    .offset     = vmstate_offset_value(_state, _field, _type),       \
+}
+
+#define VMSTATE_ARRAY(_field, _state, _num, _version, _info, _type) {\
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .num        = (_num),                                            \
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_ARRAY,                                         \
+    .offset     = vmstate_offset_array(_state, _field, _type, _num), \
+}
+
+#define VMSTATE_ARRAY_TEST(_field, _state, _num, _test, _info, _type) {\
+    .name         = (stringify(_field)),                              \
+    .field_exists = (_test),                                          \
+    .num          = (_num),                                           \
+    .info         = &(_info),                                         \
+    .size         = sizeof(_type),                                    \
+    .flags        = VMS_ARRAY,                                        \
+    .offset       = vmstate_offset_array(_state, _field, _type, _num),\
+}
+
+#define VMSTATE_SUB_ARRAY(_field, _state, _start, _num, _version, _info, _type) { \
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .num        = (_num),                                            \
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_ARRAY,                                         \
+    .offset     = vmstate_offset_sub_array(_state, _field, _type, _start), \
+}
+
+#define VMSTATE_ARRAY_INT32_UNSAFE(_field, _state, _field_num, _info, _type) {\
+    .name       = (stringify(_field)),                               \
+    .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_VARRAY_INT32,                                  \
+    .offset     = offsetof(_state, _field),                          \
+}
+
+#define VMSTATE_VARRAY_INT32(_field, _state, _field_num, _version, _info, _type) {\
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_VARRAY_INT32|VMS_POINTER,                      \
+    .offset     = vmstate_offset_pointer(_state, _field, _type),     \
+}
+
+#define VMSTATE_VARRAY_UINT32(_field, _state, _field_num, _version, _info, _type) {\
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .num_offset = vmstate_offset_value(_state, _field_num, uint32_t),\
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_VARRAY_UINT32|VMS_POINTER,                     \
+    .offset     = vmstate_offset_pointer(_state, _field, _type),     \
+}
+
+#define VMSTATE_VARRAY_UINT16_UNSAFE(_field, _state, _field_num, _version, _info, _type) {\
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_VARRAY_UINT16,                                 \
+    .offset     = offsetof(_state, _field),                          \
+}
+
+#define VMSTATE_STRUCT_TEST(_field, _state, _test, _version, _vmsd, _type) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .vmsd         = &(_vmsd),                                        \
+    .size         = sizeof(_type),                                   \
+    .flags        = VMS_STRUCT,                                      \
+    .offset       = vmstate_offset_value(_state, _field, _type),     \
+}
+
+#define VMSTATE_STRUCT_POINTER_TEST(_field, _state, _test, _vmsd, _type) { \
+    .name         = (stringify(_field)),                             \
+    .field_exists = (_test),                                         \
+    .vmsd         = &(_vmsd),                                        \
+    .size         = sizeof(_type),                                   \
+    .flags        = VMS_STRUCT|VMS_POINTER,                          \
+    .offset       = vmstate_offset_value(_state, _field, _type),     \
+}
+
+#define VMSTATE_ARRAY_OF_POINTER(_field, _state, _num, _version, _info, _type) {\
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .num        = (_num),                                            \
+    .info       = &(_info),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_ARRAY|VMS_ARRAY_OF_POINTER,                    \
+    .offset     = vmstate_offset_array(_state, _field, _type, _num), \
+}
+
+#define VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, _test, _version, _vmsd, _type) { \
+    .name         = (stringify(_field)),                             \
+    .num          = (_num),                                          \
+    .field_exists = (_test),                                         \
+    .version_id   = (_version),                                      \
+    .vmsd         = &(_vmsd),                                        \
+    .size         = sizeof(_type),                                   \
+    .flags        = VMS_STRUCT|VMS_ARRAY,                            \
+    .offset       = vmstate_offset_array(_state, _field, _type, _num),\
+}
+
+#define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \
+    .name       = (stringify(_field)),                               \
+    .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \
+    .version_id = (_version),                                        \
+    .vmsd       = &(_vmsd),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_STRUCT|VMS_VARRAY_UINT8,                       \
+    .offset     = offsetof(_state, _field),                          \
+}
+
+#define VMSTATE_STRUCT_VARRAY_POINTER_INT32(_field, _state, _field_num, _vmsd, _type) { \
+    .name       = (stringify(_field)),                               \
+    .version_id = 0,                                                 \
+    .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+    .size       = sizeof(_type),                                     \
+    .vmsd       = &(_vmsd),                                          \
+    .flags      = VMS_POINTER | VMS_VARRAY_INT32 | VMS_STRUCT,       \
+    .offset     = vmstate_offset_pointer(_state, _field, _type),     \
+}
+
+#define VMSTATE_STRUCT_VARRAY_POINTER_UINT16(_field, _state, _field_num, _vmsd, _type) { \
+    .name       = (stringify(_field)),                               \
+    .version_id = 0,                                                 \
+    .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
+    .size       = sizeof(_type),                                     \
+    .vmsd       = &(_vmsd),                                          \
+    .flags      = VMS_POINTER | VMS_VARRAY_UINT16 | VMS_STRUCT,      \
+    .offset     = vmstate_offset_pointer(_state, _field, _type),     \
+}
+
+#define VMSTATE_STRUCT_VARRAY_INT32(_field, _state, _field_num, _version, _vmsd, _type) { \
+    .name       = (stringify(_field)),                               \
+    .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+    .version_id = (_version),                                        \
+    .vmsd       = &(_vmsd),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_STRUCT|VMS_VARRAY_INT32,                       \
+    .offset     = offsetof(_state, _field),                          \
+}
+
+#define VMSTATE_STRUCT_VARRAY_UINT32(_field, _state, _field_num, _version, _vmsd, _type) { \
+    .name       = (stringify(_field)),                               \
+    .num_offset = vmstate_offset_value(_state, _field_num, uint32_t), \
+    .version_id = (_version),                                        \
+    .vmsd       = &(_vmsd),                                          \
+    .size       = sizeof(_type),                                     \
+    .flags      = VMS_STRUCT|VMS_VARRAY_UINT32,                      \
+    .offset     = offsetof(_state, _field),                          \
+}
+
+#define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .size         = (_size - _start),                                \
+    .info         = &vmstate_info_buffer,                            \
+    .flags        = VMS_BUFFER,                                      \
+    .offset       = vmstate_offset_buffer(_state, _field) + _start,  \
+}
+
+#define VMSTATE_BUFFER_MULTIPLY(_field, _state, _version, _test, _start, _field_size, _multiply) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .size_offset  = vmstate_offset_value(_state, _field_size, uint32_t),\
+    .size         = (_multiply),                                      \
+    .info         = &vmstate_info_buffer,                            \
+    .flags        = VMS_VBUFFER|VMS_MULTIPLY,                        \
+    .offset       = offsetof(_state, _field),                        \
+    .start        = (_start),                                        \
+}
+
+#define VMSTATE_VBUFFER(_field, _state, _version, _test, _start, _field_size) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .size_offset  = vmstate_offset_value(_state, _field_size, int32_t),\
+    .info         = &vmstate_info_buffer,                            \
+    .flags        = VMS_VBUFFER|VMS_POINTER,                         \
+    .offset       = offsetof(_state, _field),                        \
+    .start        = (_start),                                        \
+}
+
+#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _start, _field_size) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .size_offset  = vmstate_offset_value(_state, _field_size, uint32_t),\
+    .info         = &vmstate_info_buffer,                            \
+    .flags        = VMS_VBUFFER|VMS_POINTER,                         \
+    .offset       = offsetof(_state, _field),                        \
+    .start        = (_start),                                        \
+}
+
+#define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) { \
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .size       = (_size),                                           \
+    .info       = &(_info),                                          \
+    .flags      = VMS_BUFFER,                                        \
+    .offset     = offsetof(_state, _field),                          \
+}
+
+#define VMSTATE_UNUSED_BUFFER(_test, _version, _size) {              \
+    .name         = "unused",                                        \
+    .field_exists = (_test),                                         \
+    .version_id   = (_version),                                      \
+    .size         = (_size),                                         \
+    .info         = &vmstate_info_unused_buffer,                     \
+    .flags        = VMS_BUFFER,                                      \
+}
+
+/* _f : field name
+   _f_n : num of elements field_name
+   _n : num of elements
+   _s : struct state name
+   _v : version
+*/
+
+#define VMSTATE_SINGLE(_field, _state, _version, _info, _type)        \
+    VMSTATE_SINGLE_TEST(_field, _state, NULL, _version, _info, _type)
+
+#define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type)        \
+    VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type)
+
+#define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type)          \
+    VMSTATE_STRUCT_POINTER_TEST(_field, _state, NULL, _vmsd, _type)
+
+#define VMSTATE_STRUCT_ARRAY(_field, _state, _num, _version, _vmsd, _type) \
+    VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version,   \
+            _vmsd, _type)
+
+#define VMSTATE_BOOL_V(_f, _s, _v)                                    \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_bool, bool)
+
+#define VMSTATE_INT8_V(_f, _s, _v)                                    \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int8, int8_t)
+#define VMSTATE_INT16_V(_f, _s, _v)                                   \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int16, int16_t)
+#define VMSTATE_INT32_V(_f, _s, _v)                                   \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int32, int32_t)
+#define VMSTATE_INT64_V(_f, _s, _v)                                   \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int64, int64_t)
+
+#define VMSTATE_UINT8_V(_f, _s, _v)                                   \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint8, uint8_t)
+#define VMSTATE_UINT16_V(_f, _s, _v)                                  \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint16, uint16_t)
+#define VMSTATE_UINT32_V(_f, _s, _v)                                  \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint32, uint32_t)
+#define VMSTATE_UINT64_V(_f, _s, _v)                                  \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint64, uint64_t)
+
+#define VMSTATE_BOOL(_f, _s)                                          \
+    VMSTATE_BOOL_V(_f, _s, 0)
+
+#define VMSTATE_INT8(_f, _s)                                          \
+    VMSTATE_INT8_V(_f, _s, 0)
+#define VMSTATE_INT16(_f, _s)                                         \
+    VMSTATE_INT16_V(_f, _s, 0)
+#define VMSTATE_INT32(_f, _s)                                         \
+    VMSTATE_INT32_V(_f, _s, 0)
+#define VMSTATE_INT64(_f, _s)                                         \
+    VMSTATE_INT64_V(_f, _s, 0)
+
+#define VMSTATE_UINT8(_f, _s)                                         \
+    VMSTATE_UINT8_V(_f, _s, 0)
+#define VMSTATE_UINT16(_f, _s)                                        \
+    VMSTATE_UINT16_V(_f, _s, 0)
+#define VMSTATE_UINT32(_f, _s)                                        \
+    VMSTATE_UINT32_V(_f, _s, 0)
+#define VMSTATE_UINT64(_f, _s)                                        \
+    VMSTATE_UINT64_V(_f, _s, 0)
+
+#define VMSTATE_UINT8_EQUAL(_f, _s)                                   \
+    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint8_equal, uint8_t)
+
+#define VMSTATE_UINT16_EQUAL(_f, _s)                                  \
+    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint16_equal, uint16_t)
+
+#define VMSTATE_UINT16_EQUAL_V(_f, _s, _v)                            \
+    VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint16_equal, uint16_t)
+
+#define VMSTATE_INT32_EQUAL(_f, _s)                                   \
+    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_equal, int32_t)
+
+#define VMSTATE_UINT32_EQUAL(_f, _s)                                   \
+    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint32_equal, uint32_t)
+
+#define VMSTATE_INT32_LE(_f, _s)                                   \
+    VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
+
+#define VMSTATE_UINT8_TEST(_f, _s, _t)                               \
+    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint8, uint8_t)
+
+#define VMSTATE_UINT16_TEST(_f, _s, _t)                               \
+    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint16, uint16_t)
+
+#define VMSTATE_UINT32_TEST(_f, _s, _t)                                  \
+    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint32, uint32_t)
+
+#define VMSTATE_TIMER_TEST(_f, _s, _test)                             \
+    VMSTATE_POINTER_TEST(_f, _s, _test, vmstate_info_timer, QEMUTimer *)
+
+#define VMSTATE_TIMER(_f, _s)                                         \
+    VMSTATE_TIMER_TEST(_f, _s, NULL)
+
+#define VMSTATE_TIMER_ARRAY(_f, _s, _n)                              \
+    VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *)
+
+#define VMSTATE_BOOL_ARRAY_V(_f, _s, _n, _v)                         \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_bool, bool)
+
+#define VMSTATE_BOOL_ARRAY(_f, _s, _n)                               \
+    VMSTATE_BOOL_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT16_ARRAY_V(_f, _s, _n, _v)                         \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint16, uint16_t)
+
+#define VMSTATE_UINT16_ARRAY(_f, _s, _n)                               \
+    VMSTATE_UINT16_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT8_ARRAY_V(_f, _s, _n, _v)                         \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint8, uint8_t)
+
+#define VMSTATE_UINT8_ARRAY(_f, _s, _n)                               \
+    VMSTATE_UINT8_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v)                        \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint32, uint32_t)
+
+#define VMSTATE_UINT32_ARRAY(_f, _s, _n)                              \
+    VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v)                        \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint64, uint64_t)
+
+#define VMSTATE_UINT64_ARRAY(_f, _s, _n)                              \
+    VMSTATE_UINT64_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_INT16_ARRAY_V(_f, _s, _n, _v)                         \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int16, int16_t)
+
+#define VMSTATE_INT16_ARRAY(_f, _s, _n)                               \
+    VMSTATE_INT16_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_INT32_ARRAY_V(_f, _s, _n, _v)                         \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int32, int32_t)
+
+#define VMSTATE_INT32_ARRAY(_f, _s, _n)                               \
+    VMSTATE_INT32_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT32_SUB_ARRAY(_f, _s, _start, _num)                \
+    VMSTATE_SUB_ARRAY(_f, _s, _start, _num, 0, vmstate_info_uint32, uint32_t)
+
+#define VMSTATE_UINT32_ARRAY(_f, _s, _n)                              \
+    VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_INT64_ARRAY_V(_f, _s, _n, _v)                         \
+    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int64, int64_t)
+
+#define VMSTATE_INT64_ARRAY(_f, _s, _n)                               \
+    VMSTATE_INT64_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_BUFFER_V(_f, _s, _v)                                  \
+    VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, 0, sizeof(typeof_field(_s, _f)))
+
+#define VMSTATE_BUFFER(_f, _s)                                        \
+    VMSTATE_BUFFER_V(_f, _s, 0)
+
+#define VMSTATE_PARTIAL_BUFFER(_f, _s, _size)                         \
+    VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, 0, _size)
+
+#define VMSTATE_BUFFER_START_MIDDLE(_f, _s, _start) \
+    VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, _start, sizeof(typeof_field(_s, _f)))
+
+#define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size)                        \
+    VMSTATE_VBUFFER(_f, _s, 0, NULL, 0, _size)
+
+#define VMSTATE_PARTIAL_VBUFFER_UINT32(_f, _s, _size)                        \
+    VMSTATE_VBUFFER_UINT32(_f, _s, 0, NULL, 0, _size)
+
+#define VMSTATE_SUB_VBUFFER(_f, _s, _start, _size)                    \
+    VMSTATE_VBUFFER(_f, _s, 0, NULL, _start, _size)
+
+#define VMSTATE_BUFFER_TEST(_f, _s, _test)                            \
+    VMSTATE_STATIC_BUFFER(_f, _s, 0, _test, 0, sizeof(typeof_field(_s, _f)))
+
+#define VMSTATE_BUFFER_UNSAFE(_field, _state, _version, _size)        \
+    VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, vmstate_info_buffer, _size)
+
+#define VMSTATE_UNUSED_V(_v, _size)                                   \
+    VMSTATE_UNUSED_BUFFER(NULL, _v, _size)
+
+#define VMSTATE_UNUSED(_size)                                         \
+    VMSTATE_UNUSED_V(0, _size)
+
+#define VMSTATE_UNUSED_TEST(_test, _size)                             \
+    VMSTATE_UNUSED_BUFFER(_test, 0, _size)
+
+#define VMSTATE_END_OF_LIST()                                         \
+    {}
+
+int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
+                       void *opaque, int version_id);
+void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
+                        void *opaque);
+int vmstate_register(DeviceState *dev, int instance_id,
+                     const VMStateDescription *vmsd, void *base);
+int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
+                                   const VMStateDescription *vmsd,
+                                   void *base, int alias_id,
+                                   int required_for_version);
+void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
+                        void *opaque);
+
+struct MemoryRegion;
+void vmstate_register_ram(struct MemoryRegion *memory, DeviceState *dev);
+void vmstate_unregister_ram(struct MemoryRegion *memory, DeviceState *dev);
+void vmstate_register_ram_global(struct MemoryRegion *memory);
+
+#endif
commit 49d4d9b63ebb0d487e80d3d85a75d8256d313df9
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Jan 13 17:07:19 2012 +0100

    ptimer: move declarations to ptimer.h
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 60e1c63..1902f1a 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -11,6 +11,7 @@
 #include "qemu-timer.h"
 #include "qemu-common.h"
 #include "qdev.h"
+#include "ptimer.h"
 
 /* Common timer implementation.  */
 
diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
index 319cee1..2dfdb30 100644
--- a/hw/etraxfs_timer.c
+++ b/hw/etraxfs_timer.c
@@ -24,6 +24,7 @@
 #include "sysbus.h"
 #include "sysemu.h"
 #include "qemu-timer.h"
+#include "ptimer.h"
 
 #define D(x)
 
diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
index 62bdb03..f8a64e1 100644
--- a/hw/grlib_apbuart.c
+++ b/hw/grlib_apbuart.c
@@ -24,6 +24,7 @@
 
 #include "sysbus.h"
 #include "qemu-char.h"
+#include "ptimer.h"
 
 #include "trace.h"
 
diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c
index 5645054..9c98a83 100644
--- a/hw/grlib_gptimer.c
+++ b/hw/grlib_gptimer.c
@@ -24,6 +24,7 @@
 
 #include "sysbus.h"
 #include "qemu-timer.h"
+#include "ptimer.h"
 
 #include "trace.h"
 
diff --git a/hw/lan9118.c b/hw/lan9118.c
index 7e64c5d..341a521 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -11,6 +11,7 @@
 #include "net.h"
 #include "devices.h"
 #include "sysemu.h"
+#include "ptimer.h"
 /* For crc32 */
 #include <zlib.h>
 
diff --git a/hw/leon3.c b/hw/leon3.c
index e25bb04..71d79a6 100644
--- a/hw/leon3.c
+++ b/hw/leon3.c
@@ -23,6 +23,7 @@
  */
 #include "hw.h"
 #include "qemu-timer.h"
+#include "ptimer.h"
 #include "qemu-char.h"
 #include "sysemu.h"
 #include "boards.h"
diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c
index 445847f..115e1e9 100644
--- a/hw/lm32_timer.c
+++ b/hw/lm32_timer.c
@@ -25,6 +25,7 @@
 #include "sysbus.h"
 #include "trace.h"
 #include "qemu-timer.h"
+#include "ptimer.h"
 #include "qemu-error.h"
 
 #define DEFAULT_FREQUENCY (50*1000000)
diff --git a/hw/mcf5206.c b/hw/mcf5206.c
index 7b6d501..5110d83 100644
--- a/hw/mcf5206.c
+++ b/hw/mcf5206.c
@@ -8,6 +8,7 @@
 #include "hw.h"
 #include "mcf.h"
 #include "qemu-timer.h"
+#include "ptimer.h"
 #include "sysemu.h"
 #include "exec-memory.h"
 
diff --git a/hw/mcf5208.c b/hw/mcf5208.c
index 3b0636d..aa11a75 100644
--- a/hw/mcf5208.c
+++ b/hw/mcf5208.c
@@ -8,6 +8,7 @@
 #include "hw.h"
 #include "mcf.h"
 #include "qemu-timer.h"
+#include "ptimer.h"
 #include "sysemu.h"
 #include "net.h"
 #include "boards.h"
diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c
index 6326b70..bd2a298 100644
--- a/hw/milkymist-sysctl.c
+++ b/hw/milkymist-sysctl.c
@@ -26,6 +26,7 @@
 #include "sysemu.h"
 #include "trace.h"
 #include "qemu-timer.h"
+#include "ptimer.h"
 #include "qemu-error.h"
 
 enum {
diff --git a/hw/musicpal.c b/hw/musicpal.c
index a01e3d2..522559d 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -14,6 +14,7 @@
 #include "boards.h"
 #include "pc.h"
 #include "qemu-timer.h"
+#include "ptimer.h"
 #include "block.h"
 #include "flash.h"
 #include "console.h"
diff --git a/hw/ptimer.c b/hw/ptimer.c
index b6cabd5..de7d664 100644
--- a/hw/ptimer.c
+++ b/hw/ptimer.c
@@ -7,6 +7,7 @@
  */
 #include "hw.h"
 #include "qemu-timer.h"
+#include "ptimer.h"
 #include "host-utils.h"
 
 struct ptimer_state
diff --git a/hw/ptimer.h b/hw/ptimer.h
new file mode 100644
index 0000000..69cdddc
--- /dev/null
+++ b/hw/ptimer.h
@@ -0,0 +1,27 @@
+/*
+ * General purpose implementation of a simple periodic countdown timer.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GNU LGPL.
+ */
+#ifndef PTIMER_H
+#define PTIMER_H
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+
+/* ptimer.c */
+typedef struct ptimer_state ptimer_state;
+typedef void (*ptimer_cb)(void *opaque);
+
+ptimer_state *ptimer_init(QEMUBH *bh);
+void ptimer_set_period(ptimer_state *s, int64_t period);
+void ptimer_set_freq(ptimer_state *s, uint32_t freq);
+void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload);
+uint64_t ptimer_get_count(ptimer_state *s);
+void ptimer_set_count(ptimer_state *s, uint64_t count);
+void ptimer_run(ptimer_state *s, int oneshot);
+void ptimer_stop(ptimer_state *s);
+
+#endif
diff --git a/hw/sh_timer.c b/hw/sh_timer.c
index d2c0cec..64bf604 100644
--- a/hw/sh_timer.c
+++ b/hw/sh_timer.c
@@ -12,6 +12,7 @@
 #include "sh.h"
 #include "qemu-timer.h"
 #include "exec-memory.h"
+#include "ptimer.h"
 
 //#define DEBUG_TIMER
 
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
index 2353c43..44b500a 100644
--- a/hw/slavio_timer.c
+++ b/hw/slavio_timer.c
@@ -24,6 +24,7 @@
 
 #include "sun4m.h"
 #include "qemu-timer.h"
+#include "ptimer.h"
 #include "sysbus.h"
 #include "trace.h"
 
diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c
index 596ec0e..0da20d9 100644
--- a/hw/xilinx_axidma.c
+++ b/hw/xilinx_axidma.c
@@ -25,6 +25,7 @@
 #include "sysbus.h"
 #include "qemu-char.h"
 #include "qemu-timer.h"
+#include "ptimer.h"
 #include "qemu-log.h"
 #include "qdev-addr.h"
 
diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c
index 0b2f32a..adca53b 100644
--- a/hw/xilinx_timer.c
+++ b/hw/xilinx_timer.c
@@ -24,6 +24,7 @@
 
 #include "sysbus.h"
 #include "qemu-timer.h"
+#include "ptimer.h"
 
 #define D(x)
 
diff --git a/qemu-timer.h b/qemu-timer.h
index 67ca72e..de17f3b 100644
--- a/qemu-timer.h
+++ b/qemu-timer.h
@@ -139,19 +139,6 @@ static inline int64_t get_clock(void)
 void qemu_get_timer(QEMUFile *f, QEMUTimer *ts);
 void qemu_put_timer(QEMUFile *f, QEMUTimer *ts);
 
-/* ptimer.c */
-typedef struct ptimer_state ptimer_state;
-typedef void (*ptimer_cb)(void *opaque);
-
-ptimer_state *ptimer_init(QEMUBH *bh);
-void ptimer_set_period(ptimer_state *s, int64_t period);
-void ptimer_set_freq(ptimer_state *s, uint32_t freq);
-void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload);
-uint64_t ptimer_get_count(ptimer_state *s);
-void ptimer_set_count(ptimer_state *s, uint64_t count);
-void ptimer_run(ptimer_state *s, int oneshot);
-void ptimer_stop(ptimer_state *s);
-
 /* icount */
 int64_t cpu_get_icount(void);
 int64_t cpu_get_clock(void);
commit fbc15e27f760b45c74c9ed7de07d2a7dd13d2034
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Nov 21 19:00:31 2011 +0100

    rtc: clear non-PF bits when reinjecting on ack
    
    When an rtc interrupt is reinjected immediately after being acked,
    other interrupts should not be reinjected, so do clear their bits.
    
    Also, if the periodic interrupts have been disabled before acking,
    do not reinject, as the guest might get very confused!
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 93ceae7..657fa10 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -477,10 +477,13 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
         case RTC_REG_C:
             ret = s->cmos_data[s->cmos_index];
             qemu_irq_lower(s->irq);
+            s->cmos_data[RTC_REG_C] = 0x00;
 #ifdef TARGET_I386
             if(s->irq_coalesced &&
+                    (s->cmos_data[RTC_REG_B] & REG_B_PIE) &&
                     s->irq_reinject_on_ack_count < RTC_REINJECT_ON_ACK_COUNT) {
                 s->irq_reinject_on_ack_count++;
+                s->cmos_data[RTC_REG_C] |= REG_C_IRQF | REG_C_PF;
                 apic_reset_irq_delivered();
                 DPRINTF_C("cmos: injecting on ack\n");
                 qemu_irq_raise(s->irq);
@@ -489,11 +492,8 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
                     DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
                               s->irq_coalesced);
                 }
-                break;
             }
 #endif
-
-            s->cmos_data[RTC_REG_C] = 0x00;
             break;
         default:
             ret = s->cmos_data[s->cmos_index];
commit 663447d4ead009efd8959fe9f7055398dacd6db4
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Nov 21 19:00:30 2011 +0100

    rtc: raise PF bit when the periodic timer triggers but PIE=0
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index c482d3f..93ceae7 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -179,8 +179,9 @@ static void rtc_periodic_timer(void *opaque)
     RTCState *s = opaque;
 
     rtc_timer_update(s, s->next_periodic_time);
+    s->cmos_data[RTC_REG_C] |= REG_C_PF;
     if (s->cmos_data[RTC_REG_B] & REG_B_PIE) {
-        s->cmos_data[RTC_REG_C] |= 0xc0;
+        s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
 #ifdef TARGET_I386
         if(rtc_td_hack) {
             if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT)
commit eea86673608692c2345cfb3edd72eb9958adad7f
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Nov 21 19:00:29 2011 +0100

    rtc: raise AF bit when the alarm is encountered but AIE=0
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 65ed779..c482d3f 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -425,16 +425,17 @@ static void rtc_update_second2(void *opaque)
     }
 
     /* check alarm */
-    if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
-        if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
-             rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]) == s->current_tm.tm_sec) &&
-            ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
-             rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]) == s->current_tm.tm_min) &&
-            ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
-             rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]) == s->current_tm.tm_hour)) {
-
-            s->cmos_data[RTC_REG_C] |= 0xa0;
+    if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
+         rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]) == s->current_tm.tm_sec) &&
+        ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
+         rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]) == s->current_tm.tm_min) &&
+        ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
+         rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]) == s->current_tm.tm_hour)) {
+
+        s->cmos_data[RTC_REG_C] |= REG_C_AF;
+        if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
             qemu_irq_raise(s->irq);
+            s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
         }
     }
 
commit 3b89eb43b66eec34277fddfce610ac1ec7c78dba
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Nov 21 19:00:28 2011 +0100

    rtc: fix 12-hour mode
    
    Hours in 12-hour mode are in the 1-12 range, not 0-11.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 9cbd052..65ed779 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -296,9 +296,11 @@ static void rtc_set_time(RTCState *s)
     tm->tm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]);
     tm->tm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]);
     tm->tm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
-    if (!(s->cmos_data[RTC_REG_B] & REG_B_24H) &&
-        (s->cmos_data[RTC_HOURS] & 0x80)) {
-        tm->tm_hour += 12;
+    if (!(s->cmos_data[RTC_REG_B] & REG_B_24H)) {
+        tm->tm_hour %= 12;
+        if (s->cmos_data[RTC_HOURS] & 0x80) {
+            tm->tm_hour += 12;
+        }
     }
     tm->tm_wday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1;
     tm->tm_mday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
@@ -320,7 +322,8 @@ static void rtc_copy_date(RTCState *s)
         s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour);
     } else {
         /* 12 hour format */
-        s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour % 12);
+        int h = (tm->tm_hour % 12) ? tm->tm_hour % 12 : 12;
+        s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, h);
         if (tm->tm_hour >= 12)
             s->cmos_data[RTC_HOURS] |= 0x80;
     }
commit 024a6fbdb9d8cbc4d7f833b23db51c9d1004bc47
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Jan 13 07:45:55 2012 -0600

    qdev: fix device_del by refactoring reference counting
    
    Commit 8eb0283 broken device_del by having too overzealous reference counting
    checks.  Move the reference count checks to qdev_free(), make sure to remove
    the parent link on free, and decrement the reference count on property removal.
    
    Reported-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev.c b/hw/qdev.c
index d0cf66d..e59f345 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -376,11 +376,6 @@ int qdev_unplug(DeviceState *dev)
     }
     assert(dev->info->unplug != NULL);
 
-    if (dev->ref != 0) {
-        qerror_report(QERR_DEVICE_IN_USE, dev->id?:"");
-        return -1;
-    }
-
     qdev_hot_removed = true;
 
     return dev->info->unplug(dev);
@@ -465,6 +460,29 @@ static void qdev_property_del_all(DeviceState *dev)
     }
 }
 
+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)
 {
@@ -491,6 +509,12 @@ void qdev_free(DeviceState *dev)
             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);
 }
 
@@ -1239,6 +1263,14 @@ static void qdev_get_child_property(DeviceState *dev, Visitor *v, void *opaque,
     g_free(path);
 }
 
+static void qdev_release_child_property(DeviceState *dev, const char *name,
+                                        void *opaque)
+{
+    DeviceState *child = opaque;
+
+    qdev_unref(child);
+}
+
 void qdev_property_add_child(DeviceState *dev, const char *name,
                              DeviceState *child, Error **errp)
 {
@@ -1247,7 +1279,8 @@ void qdev_property_add_child(DeviceState *dev, const char *name,
     type = g_strdup_printf("child<%s>", child->info->name);
 
     qdev_property_add(dev, name, type, qdev_get_child_property,
-                      NULL, NULL, child, errp);
+                      NULL, qdev_release_child_property,
+                      child, errp);
 
     qdev_ref(child);
     g_assert(child->parent == NULL);
commit 607a2c72e52d6a7050c0eae1076b0b2976180d3e
Merge: 20f8bd4... f725327...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Jan 13 10:17:49 2012 -0600

    Merge remote-tracking branch 'stefanha/trivial-patches' into HEAD
    
    * stefanha/trivial-patches:
      bt-host: add missing break statement
      virtfs-proxy-helper: Add missing printf format attribute
      virtfs-proxy-helper: Clean include files
      virtfs-proxy-helper: Fix compilation on newer systems
      hmp: Fix freeing of PciInfoList
      Add 'fall through' comments to case statements without break
      omap_dss: correct chip[1] index in RFBI_READ/RFBI_STATUS
      vnc: fix no-lock-key-sync strncmp() length
      vvfat: avoid leaking file descriptor in commit_one_file()
      Spelling fixes in comments and documentation
      tcg-arm: fix a typo in comments
      configure: Modify detection of supported warning options

commit 20f8bd483c3ead658df7563d00768a9874ebb6f0
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Fri Jan 13 16:01:40 2012 +0100

    target-i386: fix compilation with --enable-debug-tcg
    
    Commit 2355c16e74ffa4d14e7fc2b4a23b055565ac0221 introduced a new ldmxcsr
    helper taking an i32 argument, but the helper is actually passed a long.
    Fix that by truncating the long to i32.
    
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-i386/translate.c b/target-i386/translate.c
index b9839c5..860b4a3 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -7544,7 +7544,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
             gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
             if (op == 2) {
                 gen_op_ld_T0_A0(OT_LONG + s->mem_index);
-                gen_helper_ldmxcsr(cpu_T[0]);
+                tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
+                gen_helper_ldmxcsr(cpu_tmp2_i32);
             } else {
                 tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, mxcsr));
                 gen_op_st_T0_A0(OT_LONG + s->mem_index);
commit f7253270fc66a60e4faf639a3c4ce0b352553b24
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Thu Jan 12 14:17:04 2012 +0000

    bt-host: add missing break statement
    
    The switch statement in bt_host_read() is missing a break in one case.
    Andrzej Zaborowski <andrew.zaborowski at intel.com> confirmed that this is
    not an intentional fall-through.
    
    Reviewed-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/bt-host.c b/bt-host.c
index df5b7cd..0d3ad28 100644
--- a/bt-host.c
+++ b/bt-host.c
@@ -130,6 +130,7 @@ static void bt_host_read(void *opaque)
             pktlen = MIN(pkt[2] + 3, s->len);
             s->len -= pktlen;
             pkt += pktlen;
+            break;
 
         default:
         bad_pkt:
commit c5c7d3f0a79a977955e9df436cf9ca17269b8783
Author: Stefan Weil <sw at weilnetz.de>
Date:   Wed Jan 11 19:47:37 2012 +0100

    virtfs-proxy-helper: Add missing printf format attribute
    
    Every function with printf like arguments must have it
    (see file HACKING), so add it.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index 21e9b16..4a507d8 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -54,7 +54,7 @@ static struct option helper_opts[] = {
 static bool is_daemon;
 static bool get_version; /* IOC getversion IOCTL supported */
 
-static void do_log(int loglevel, const char *format, ...)
+static void GCC_FMT_ATTR(2, 3) do_log(int loglevel, const char *format, ...)
 {
     va_list ap;
 
commit e7e4a6ccae023ab4b9650aed6af369088ef08e3b
Author: Stefan Weil <sw at weilnetz.de>
Date:   Wed Jan 11 19:34:30 2012 +0100

    virtfs-proxy-helper: Clean include files
    
    The common standard include files are already included via qemu-common.h,
    and for the socket related include files there is qemu_socket.h, so the
    code can be reduced by some lines.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index ce7eb79..21e9b16 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -8,31 +8,20 @@
  * This work is licensed under the terms of the GNU GPL, version 2. See
  * the COPYING file in the top-level directory.
  */
-#include <stdio.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <sys/un.h>
-#include <limits.h>
-#include <signal.h>
-#include <errno.h>
-#include <stdlib.h>
+
 #include <sys/resource.h>
-#include <sys/stat.h>
 #include <getopt.h>
-#include <unistd.h>
 #include <syslog.h>
 #include <sys/capability.h>
 #include <sys/fsuid.h>
-#include <stdarg.h>
-#include <stdbool.h>
 #include <sys/vfs.h>
-#include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <linux/fs.h>
 #ifdef CONFIG_LINUX_MAGIC_H
 #include <linux/magic.h>
 #endif
 #include "qemu-common.h"
+#include "qemu_socket.h"
 #include "qemu-xattr.h"
 #include "virtio-9p-marshal.h"
 #include "hw/9pfs/virtio-9p-proxy.h"
commit 822b635d903306e2ea0b7f835d4a5afc3a66e996
Author: Stefan Weil <sw at weilnetz.de>
Date:   Wed Jan 11 19:34:29 2012 +0100

    virtfs-proxy-helper: Fix compilation on newer systems
    
    Include file attr/xattr.h is not available on "newer" systems
    (for example Fedora 12 or Debian Squeeze).
    
    See comments in qemu-xattr.h for more information.
    This file handles the system dependencies automatically.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
index 7f8def5..ce7eb79 100644
--- a/fsdev/virtfs-proxy-helper.c
+++ b/fsdev/virtfs-proxy-helper.c
@@ -27,13 +27,13 @@
 #include <stdbool.h>
 #include <sys/vfs.h>
 #include <sys/stat.h>
-#include <attr/xattr.h>
 #include <sys/ioctl.h>
 #include <linux/fs.h>
 #ifdef CONFIG_LINUX_MAGIC_H
 #include <linux/magic.h>
 #endif
 #include "qemu-common.h"
+#include "qemu-xattr.h"
 #include "virtio-9p-marshal.h"
 #include "hw/9pfs/virtio-9p-proxy.h"
 #include "fsdev/virtio-9p-marshal.h"
commit f46cee374218dc5ebda3e7aa6996ef7f1b90eb7c
Author: Stefan Berger <stefanb at linux.vnet.ibm.com>
Date:   Wed Jan 11 10:51:52 2012 -0500

    hmp: Fix freeing of PciInfoList
    
    Remember the original PciInfoList in info_list and use
    the info variable to traverse the list.
    
    Signed-off-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hmp.c b/hmp.c
index e7659d5..fd4f755 100644
--- a/hmp.c
+++ b/hmp.c
@@ -486,17 +486,17 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
 
 void hmp_info_pci(Monitor *mon)
 {
-    PciInfoList *info;
+    PciInfoList *info_list, *info;
     Error *err = NULL;
 
-    info = qmp_query_pci(&err);
+    info_list = qmp_query_pci(&err);
     if (err) {
         monitor_printf(mon, "PCI devices not supported\n");
         error_free(err);
         return;
     }
 
-    for (; info; info = info->next) {
+    for (info = info_list; info; info = info->next) {
         PciDeviceInfoList *dev;
 
         for (dev = info->value->devices; dev; dev = dev->next) {
@@ -504,7 +504,7 @@ void hmp_info_pci(Monitor *mon)
         }
     }
 
-    qapi_free_PciInfoList(info);
+    qapi_free_PciInfoList(info_list);
 }
 
 void hmp_quit(Monitor *mon, const QDict *qdict)
commit 0b0404bf84432f0ee74840d674b93bacee7eee68
Author: Stefan Weil <sw at weilnetz.de>
Date:   Mon Jan 9 18:29:51 2012 +0100

    Add 'fall through' comments to case statements without break
    
    These comments are used by static code analysis tools and in code reviews
    to avoid false warnings because of missing break statements.
    
    The case statements handled here were reported by coverity.
    
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/pcnet.c b/hw/pcnet.c
index cba253b..306dc6e 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -1505,6 +1505,7 @@ static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val)
 #ifdef PCNET_DEBUG
        printf("BCR_SWS=0x%04x\n", val);
 #endif
+        /* fall through */
     case BCR_LNKST:
     case BCR_LED1:
     case BCR_LED2:
diff --git a/json-lexer.c b/json-lexer.c
index c21338f..3cd3285 100644
--- a/json-lexer.c
+++ b/json-lexer.c
@@ -301,6 +301,7 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
         case JSON_KEYWORD:
         case JSON_STRING:
             lexer->emit(lexer, lexer->token, new_state, lexer->x, lexer->y);
+            /* fall through */
         case JSON_SKIP:
             QDECREF(lexer->token);
             lexer->token = qstring_new();
diff --git a/qemu-option.c b/qemu-option.c
index 6b23c31..a303f87 100644
--- a/qemu-option.c
+++ b/qemu-option.c
@@ -214,13 +214,17 @@ static int parse_option_size(const char *name, const char *value, uint64_t *ret)
         switch (*postfix) {
         case 'T':
             sizef *= 1024;
+            /* fall through */
         case 'G':
             sizef *= 1024;
+            /* fall through */
         case 'M':
             sizef *= 1024;
+            /* fall through */
         case 'K':
         case 'k':
             sizef *= 1024;
+            /* fall through */
         case 'b':
         case '\0':
             *ret = (uint64_t) sizef;
commit 3c8359d11aee9d3fdcab0f184605f603f91f34f7
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Sat Jan 7 11:59:59 2012 +0000

    omap_dss: correct chip[1] index in RFBI_READ/RFBI_STATUS
    
    The RFBI_READ/RFBI_STATUS code incorrectly uses chip[0] when it should
    be using chip[1].  Andrzej Zaborowski <balrog at zabor.org> confirmed this
    bug since I don't know this code well.
    
    Reported-by: Dr David Alan Gilbert <davidagilbert at uk.ibm.com>
    Reviewed-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/omap_dss.c b/hw/omap_dss.c
index ede640b..86ed6ea 100644
--- a/hw/omap_dss.c
+++ b/hw/omap_dss.c
@@ -793,7 +793,7 @@ static void omap_rfbi_write(void *opaque, target_phys_addr_t addr,
         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
             s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
         else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
-            s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
+            s->rfbi.rxbuf = s->rfbi.chip[1]->read(s->rfbi.chip[1]->opaque, 1);
         if (!-- s->rfbi.pixels)
             omap_rfbi_transfer_stop(s);
         break;
@@ -802,7 +802,7 @@ static void omap_rfbi_write(void *opaque, target_phys_addr_t addr,
         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
             s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
         else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
-            s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
+            s->rfbi.rxbuf = s->rfbi.chip[1]->read(s->rfbi.chip[1]->opaque, 0);
         if (!-- s->rfbi.pixels)
             omap_rfbi_transfer_stop(s);
         break;
commit cee8e6add587e20ed1f4c5a95031a1697d7375b1
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Fri Jan 6 16:57:45 2012 +0000

    vnc: fix no-lock-key-sync strncmp() length
    
    The no-lock-key-sync option is being parsed incorrectly because of an
    outdated strcmp() length value.  Use the correct length so that invalid
    option names do not match.
    
    Reported-by: Dr David Alan Gilbert <davidagilbert at uk.ibm.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/ui/vnc.c b/ui/vnc.c
index 6767ada..1869a7a 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2763,7 +2763,7 @@ int vnc_display_open(DisplayState *ds, const char *display)
             password = 1; /* Require password auth */
         } else if (strncmp(options, "reverse", 7) == 0) {
             reverse = 1;
-        } else if (strncmp(options, "no-lock-key-sync", 9) == 0) {
+        } else if (strncmp(options, "no-lock-key-sync", 16) == 0) {
             lock_key_sync = 0;
 #ifdef CONFIG_VNC_SASL
         } else if (strncmp(options, "sasl", 4) == 0) {
commit 8d98734651a8a601980b6e57788f2ed6a4ea620a
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Fri Jan 6 16:57:44 2012 +0000

    vvfat: avoid leaking file descriptor in commit_one_file()
    
    Reported-by: Dr David Alan Gilbert <davidagilbert at uk.ibm.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/block/vvfat.c b/block/vvfat.c
index eeffc4a..9ef21dd 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -2218,6 +2218,7 @@ static int commit_one_file(BDRVVVFATState* s,
     }
     if (offset > 0) {
         if (lseek(fd, offset, SEEK_SET) != offset) {
+            close(fd);
             g_free(cluster);
             return -3;
         }
@@ -2238,11 +2239,13 @@ static int commit_one_file(BDRVVVFATState* s,
 	    (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
 
         if (ret < 0) {
+            close(fd);
             g_free(cluster);
             return ret;
         }
 
         if (write(fd, cluster, rest_size) < 0) {
+            close(fd);
             g_free(cluster);
             return -2;
         }
commit dabdf394258aaa040fa0e754d6d05d7833542033
Author: Stefan Weil <sw at weilnetz.de>
Date:   Sun Jan 8 19:35:09 2012 +0100

    Spelling fixes in comments and documentation
    
    Codespell detected these new spelling issues.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/docs/writing-qmp-commands.txt b/docs/writing-qmp-commands.txt
index 0472fc3..0ad51aa 100644
--- a/docs/writing-qmp-commands.txt
+++ b/docs/writing-qmp-commands.txt
@@ -435,7 +435,7 @@ There are a number of things to be noticed:
    for all QMP functions)
 3. The "clock" variable (which will point to our QAPI type instance) is
    allocated by the regular g_malloc0() function. Note that we chose to
-   initialize the memory to zero. This is recomended for all QAPI types, as
+   initialize the memory to zero. This is recommended for all QAPI types, as
    it helps avoiding bad surprises (specially with booleans)
 4. Remember that "next_deadline" is optional? All optional members have a
    'has_TYPE_NAME' member that should be properly set by the implementation,
diff --git a/memory.h b/memory.h
index 70f57fb..d48b08b 100644
--- a/memory.h
+++ b/memory.h
@@ -561,7 +561,7 @@ void memory_region_add_subregion_overlap(MemoryRegion *mr,
  * memory_region_get_ram_addr: Get the ram address associated with a memory
  *                             region
  *
- * DO NOT USE THIS FUCNTION.  This is a temporary workaround while the Xen
+ * DO NOT USE THIS FUNCTION.  This is a temporary workaround while the Xen
  * code is being reworked.
  */
 ram_addr_t memory_region_get_ram_addr(MemoryRegion *mr);
@@ -650,7 +650,7 @@ void memory_global_sync_dirty_bitmap(MemoryRegion *address_space);
  * memory_region_transaction_begin: Start a transaction.
  *
  * During a transaction, changes will be accumulated and made visible
- * only when the transaction ends (is commited).
+ * only when the transaction ends (is committed).
  */
 void memory_region_transaction_begin(void);
 
diff --git a/qemu-ga.c b/qemu-ga.c
index 200bb15..29e4f64 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -92,7 +92,7 @@ static void usage(const char *cmd)
 "  -v, --verbose     log extra debugging information\n"
 "  -V, --version     print version information and exit\n"
 "  -d, --daemonize   become a daemon\n"
-"  -b, --blacklist   comma-seperated list of RPCs to disable (no spaces, \"?\""
+"  -b, --blacklist   comma-separated list of RPCs to disable (no spaces, \"?\""
 "                    to list available RPCs)\n"
 "  -h, --help        display this help and exit\n"
 "\n"
commit 5c84bd904ba0aacdb295df5ff7c90ef941f469bb
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Sat Jan 7 21:00:25 2012 +0100

    tcg-arm: fix a typo in comments
    
    ARM still doesn't support 16GB buffers in 32-bit modes, replace the
    16GB by 16MB in the comment.
    
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/exec.c b/exec.c
index b1d6602..7f9f730 100644
--- a/exec.c
+++ b/exec.c
@@ -511,7 +511,7 @@ static void code_gen_alloc(unsigned long tb_size)
         if (code_gen_buffer_size > (512 * 1024 * 1024))
             code_gen_buffer_size = (512 * 1024 * 1024);
 #elif defined(__arm__)
-        /* Keep the buffer no bigger than 16GB to branch between blocks */
+        /* Keep the buffer no bigger than 16MB to branch between blocks */
         if (code_gen_buffer_size > 16 * 1024 * 1024)
             code_gen_buffer_size = 16 * 1024 * 1024;
 #elif defined(__s390x__)
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index 1d32798..5b233f5 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -843,7 +843,7 @@ static inline void tcg_out_st8(TCGContext *s, int cond,
 }
 
 /* The _goto case is normally between TBs within the same code buffer,
- * and with the code buffer limited to 16GB we shouldn't need the long
+ * and with the code buffer limited to 16MB we shouldn't need the long
  * case.
  *
  * .... except to the prologue that is in its own buffer.
commit bd947d30b6757067fa8f8407ef248fd8645383ee
Author: Stefan Weil <sw at weilnetz.de>
Date:   Wed Jan 4 22:47:16 2012 +0100

    configure: Modify detection of supported warning options
    
    Reversing the order of the warning options and -Werror is important
    when clang is used instead of gcc. It changes nothing for gcc.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/configure b/configure
index eb9a01d..467e87b 100755
--- a/configure
+++ b/configure
@@ -1105,7 +1105,7 @@ cat > $TMPC << EOF
 int main(void) { return 0; }
 EOF
 for flag in $gcc_flags; do
-    if compile_prog "$flag -Werror" "" ; then
+    if compile_prog "-Werror $flag" "" ; then
 	QEMU_CFLAGS="$QEMU_CFLAGS $flag"
     fi
 done
commit bee5a5fb11de34aa422cfc830adbd51cfc8f5b55
Author: Edgar E. Iglesias <edgar.iglesias at gmail.com>
Date:   Fri Jan 13 11:09:56 2012 +0100

    cris: Update paths to match the move of tests/cris
    
    Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>

diff --git a/tests/tcg/cris/Makefile b/tests/tcg/cris/Makefile
index b86bcad..d34bfd8 100644
--- a/tests/tcg/cris/Makefile
+++ b/tests/tcg/cris/Makefile
@@ -1,7 +1,7 @@
--include ../../config-host.mak
+-include ../../../config-host.mak
 
 CROSS=crisv32-axis-linux-gnu-
-SIM=../../cris-linux-user/qemu-cris -L ./
+SIM=../../../cris-linux-user/qemu-cris -L ./
 SIMG=cris-axis-linux-gnu-run --sysroot=./
 
 CC      = $(CROSS)gcc
@@ -14,7 +14,7 @@ OBJCOPY = $(CROSS)objcopy
 # we rely on GCC inline:ing the stuff we tell it to in many places here.
 CFLAGS  = -Winline -Wall -g -O2 -static
 NOSTDFLAGS = -nostartfiles -nostdlib
-ASFLAGS += -g -Wa,-I,$(SRC_PATH)/tests/cris/
+ASFLAGS += -g -Wa,-I,$(SRC_PATH)/tests/tcg/cris/
 LDLIBS  =
 NOSTDLIBS = -lgcc
 
@@ -124,10 +124,10 @@ TESTCASES += check_gcctorture_pr28634-1.ctst
 
 all: build
 
-%.o: $(SRC_PATH)/tests/cris/%.c
+%.o: $(SRC_PATH)/tests/tcg/cris/%.c
 	$(CC) $(CFLAGS) -c $< -o $@
 
-%.o: $(SRC_PATH)/tests/cris/%.s
+%.o: $(SRC_PATH)/tests/tcg/cris/%.s
 	$(AS) $(ASFLAGS) -c $< -o $@
 
 %.tst: %.o
commit b870472db5c90d3c96f4b85fbdfce87ce8076fc8
Author: H. Peter Anvin <hpa at linux.intel.com>
Date:   Fri Sep 10 14:47:56 2010 -0700

    usb: add audio device model
    
    This brings a usb audio device to qemu.  Output only, fixed at
    16bit stereo @ 480000 Hz.  Based on a patch from
    H. Peter Anvin <hpa at linux.intel.com>
    
    Usage: add '-device usb-audio' to your qemu command line.
    
    Works sorta ok on a idle machine.  Known issues:
    
     * Is *very* sensitive to latencies.
     * Burns quite some CPU due to usb polling.
    
    In short:  It brings the qemu usb emulation to its limits.  Enjoy!
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/Makefile.objs b/Makefile.objs
index 4f6d26c..8956cb9 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -102,7 +102,7 @@ common-obj-y += scsi-disk.o cdrom.o
 common-obj-y += scsi-generic.o scsi-bus.o
 common-obj-y += hid.o
 common-obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
-common-obj-y += usb-serial.o usb-net.o usb-bus.o usb-desc.o
+common-obj-y += usb-serial.o usb-net.o usb-bus.o usb-desc.o usb-audio.o
 common-obj-$(CONFIG_SSI) += ssi.o
 common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
 common-obj-$(CONFIG_SD) += sd.o
diff --git a/hw/usb-audio.c b/hw/usb-audio.c
new file mode 100644
index 0000000..b22d578
--- /dev/null
+++ b/hw/usb-audio.c
@@ -0,0 +1,704 @@
+/*
+ * QEMU USB audio device
+ *
+ * written by:
+ *  H. Peter Anvin <hpa at linux.intel.com>
+ *  Gerd Hoffmann <kraxel at 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 struct USBDeviceInfo usb_audio_info = {
+    .product_desc   = "QEMU USB Audio Interface",
+    .usbdevice_name = "audio",
+    .qdev.name      = "usb-audio",
+    .qdev.size      = sizeof(USBAudioState),
+    .qdev.vmsd      = &vmstate_usb_audio,
+    .usb_desc       = &desc_audio,
+    .init           = usb_audio_initfn,
+    .handle_packet  = usb_generic_handle_packet,
+    .handle_reset   = usb_audio_handle_reset,
+    .handle_control = usb_audio_handle_control,
+    .handle_data    = usb_audio_handle_data,
+    .handle_destroy = usb_audio_handle_destroy,
+    .set_interface  = usb_audio_set_interface,
+    .qdev.props = (Property[]) {
+        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_register_devices(void)
+{
+    usb_qdev_register(&usb_audio_info);
+}
+
+device_init(usb_audio_register_devices)
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 5622bed..2f527a8 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
diff --git a/hw/usb.h b/hw/usb.h
index 1496f76..b2c9479 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -79,6 +79,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,6 +137,8 @@
 #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
commit cc5f13956c3e681d5974bc81b6d275c19666af4b
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Aug 10 14:10:04 2011 +0200

    usb-desc: audio endpoint support
    
    Add support for audio endpoints which have two more fields in the
    descriptor.  Also add support for extra class specific endpoint
    descriptors.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-desc.c b/hw/usb-desc.c
index b9996a1..9c38661 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)
diff --git a/hw/usb-desc.h b/hw/usb-desc.h
index 5c14e4a..d6e07ea 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 {
commit 1de14d43e29b8f1fff8bcbf18f300adeb3eabc1d
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Aug 30 13:21:27 2011 +0200

    usb: track altsetting in USBDevice
    
    Also handle {GET,SET}_INTERFACE in common code (usb-desc.c).
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index f30eec1..0c1270b 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,
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index cd349f3..e9935ad 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -611,14 +611,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");
diff --git a/hw/usb-desc.c b/hw/usb-desc.c
index b52561a..b9996a1 100644
--- a/hw/usb-desc.c
+++ b/hw/usb-desc.c
@@ -223,6 +223,54 @@ int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
 
 /* ------------------------------------------------------------------ */
 
+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;
+
+    if (dev->info->set_interface && old != value) {
+        dev->info->set_interface(dev, index, old, value);
+    }
+    return 0;
+}
+
 static int usb_desc_set_config(USBDevice *dev, int value)
 {
     int i;
@@ -237,12 +285,22 @@ static int usb_desc_set_config(USBDevice *dev, int 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;
 }
 
@@ -479,6 +537,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-hid.c b/hw/usb-hid.c
index a110c74..997f828 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) {
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index e195937..069611b 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;
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index e427296..186831d 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.  */
diff --git a/hw/usb-net.c b/hw/usb-net.c
index f91fa32..5622bed 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1098,17 +1098,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: "
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index 7dbf6df..e3c8238 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;
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 2558006..61d5b18 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);
diff --git a/hw/usb.h b/hw/usb.h
index 1ef53a1..1496f76 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -161,6 +161,9 @@ struct USBDescString {
     QLIST_ENTRY(USBDescString) next;
 };
 
+#define USB_MAX_ENDPOINTS  15
+#define USB_MAX_INTERFACES 16
+
 /* definition of a USB device */
 struct USBDevice {
     DeviceState qdev;
@@ -191,7 +194,9 @@ struct USBDevice {
 
     int configuration;
     int ninterfaces;
+    int altsetting[USB_MAX_INTERFACES];
     const USBDescConfig *config;
+    const USBDescIface  *ifaces[USB_MAX_INTERFACES];
 };
 
 struct USBDeviceInfo {
@@ -244,6 +249,9 @@ 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;
 
diff --git a/trace-events b/trace-events
index c18435b..834eb7f 100644
--- a/trace-events
+++ b/trace-events
@@ -246,6 +246,7 @@ usb_desc_other_speed_config(int addr, int index, int len, int ret) "dev %d query
 usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d"
 usb_set_addr(int addr) "dev %d"
 usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d"
+usb_set_interface(int addr, int iface, int alt, int ret) "dev %d, interface %d, altsetting %d, ret %d"
 usb_clear_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
 usb_set_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
 
diff --git a/usb-linux.c b/usb-linux.c
index 3aaa93b..ded0726 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -544,6 +544,10 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
     int interface, nb_interfaces;
     int ret, i;
 
+    for (i = 0; i < USB_MAX_INTERFACES; i++) {
+        dev->dev.altsetting[i] = 0;
+    }
+
     if (configuration == 0) { /* address state - ignore */
         dev->dev.ninterfaces   = 0;
         dev->dev.configuration = 0;
@@ -997,6 +1001,10 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
         }
     }
 
+    if (iface >= USB_MAX_INTERFACES) {
+        return USB_RET_STALL;
+    }
+
     si.interface  = iface;
     si.altsetting = alt;
     ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
@@ -1007,6 +1015,8 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
     if (ret < 0) {
         return ctrl_error();
     }
+
+    s->dev.altsetting[iface] = alt;
     usb_linux_update_endp_table(s);
     return 0;
 }
commit 65360511a2eeab8b671722df6634dd674cc4a5d6
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Aug 30 11:11:29 2011 +0200

    usb: track configuration and interface count in USBDevice.
    
    Move fields from USBHostDevice to USBDevice.
    Add bits to usb-desc.c to fill them for emulated devices too.
    Also allow to set configuration 0 (== None) for emulated devices.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-desc.c b/hw/usb-desc.c
index ae2d384..b52561a 100644
--- a/hw/usb-desc.c
+++ b/hw/usb-desc.c
@@ -223,6 +223,29 @@ int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
 
 /* ------------------------------------------------------------------ */
 
+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;
+            }
+        }
+        if (i < dev->device->bNumConfigurations) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
 static void usb_desc_setdefaults(USBDevice *dev)
 {
     const USBDesc *desc = dev->info->usb_desc;
@@ -237,7 +260,7 @@ 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)
@@ -408,7 +431,7 @@ 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;
+    int ret = -1;
 
     assert(desc != NULL);
     switch(request) {
@@ -427,12 +450,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;
 
diff --git a/hw/usb.h b/hw/usb.h
index c6e1870..1ef53a1 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -188,6 +188,9 @@ struct USBDevice {
 
     QLIST_HEAD(, USBDescString) strings;
     const USBDescDevice *device;
+
+    int configuration;
+    int ninterfaces;
     const USBDescConfig *config;
 };
 
diff --git a/usb-linux.c b/usb-linux.c
index c68e194..3aaa93b 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -106,8 +106,6 @@ typedef struct USBHostDevice {
 
     uint8_t   descr[8192];
     int       descr_len;
-    int       configuration;
-    int       ninterfaces;
     int       closing;
     uint32_t  iso_urb_count;
     Notifier  exit;
@@ -547,8 +545,8 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
     int ret, i;
 
     if (configuration == 0) { /* address state - ignore */
-        dev->ninterfaces   = 0;
-        dev->configuration = 0;
+        dev->dev.ninterfaces   = 0;
+        dev->dev.configuration = 0;
         return 1;
     }
 
@@ -606,8 +604,8 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
     trace_usb_host_claim_interfaces(dev->bus_num, dev->addr,
                                     nb_interfaces, configuration);
 
-    dev->ninterfaces   = nb_interfaces;
-    dev->configuration = configuration;
+    dev->dev.ninterfaces   = nb_interfaces;
+    dev->dev.configuration = configuration;
     return 1;
 
 fail:
@@ -624,7 +622,7 @@ static int usb_host_release_interfaces(USBHostDevice *s)
 
     trace_usb_host_release_interfaces(s->bus_num, s->addr);
 
-    for (i = 0; i < s->ninterfaces; i++) {
+    for (i = 0; i < s->dev.ninterfaces; i++) {
         ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
         if (ret < 0) {
             perror("USBDEVFS_RELEASEINTERFACE");
@@ -1123,7 +1121,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
         s->ep_out[i].type = INVALID_EP_TYPE;
     }
 
-    if (s->configuration == 0) {
+    if (s->dev.configuration == 0) {
         /* not configured yet -- leave all endpoints disabled */
         return 0;
     }
@@ -1138,12 +1136,11 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
         if (descriptors[i + 1] != USB_DT_CONFIG) {
             fprintf(stderr, "invalid descriptor data\n");
             return 1;
-        } else if (descriptors[i + 5] != s->configuration) {
-            DPRINTF("not requested configuration %d\n", s->configuration);
+        } else if (descriptors[i + 5] != s->dev.configuration) {
+            DPRINTF("not requested configuration %d\n", s->dev.configuration);
             i += (descriptors[i + 3] << 8) + descriptors[i + 2];
             continue;
         }
-
         i += descriptors[i];
 
         if (descriptors[i + 1] != USB_DT_INTERFACE ||
@@ -1154,7 +1151,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
         }
 
         interface = descriptors[i + 2];
-        alt_interface = usb_linux_get_alt_setting(s, s->configuration,
+        alt_interface = usb_linux_get_alt_setting(s, s->dev.configuration,
                                                   interface);
 
         /* the current interface descriptor is the active interface
commit 097db4384860b4363364eb531285296f616d89e5
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Dec 16 11:54:11 2011 +0100

    usb-host: rip out legacy procfs support
    
    This patch removes support for parsing /proc/bus/usb/devices for device
    discovery.  The code lacks a few features compared to the sysfs code and
    is also bitrotting as everybody has sysfs these days.
    
    This implies having sysfs mounted is mandatory now to use the usb-host
    driver.  udev isn't required though.  qemu will prefer the udev-managed
    device nodes below /dev/bus/usb, but in case this directory isn't preset
    qemu will use the device nodes below /proc/bus/usb (default usbfs mount
    point).
    
    Bottom line: make sure you have both sysfs and usbfs mounted properly,
    and everything should continue to work as it did before.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/usb-linux.c b/usb-linux.c
index 749ce71..c68e194 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -66,23 +66,9 @@ typedef int USBScanFunc(void *opaque, int bus_num, int addr, const char *port,
 #define DPRINTF(...)
 #endif
 
-#define USBDBG_DEVOPENED "husb: opened %s/devices\n"
-
-#define USBPROCBUS_PATH "/proc/bus/usb"
 #define PRODUCT_NAME_SZ 32
 #define MAX_ENDPOINTS 15
 #define MAX_PORTLEN 16
-#define USBDEVBUS_PATH "/dev/bus/usb"
-#define USBSYSBUS_PATH "/sys/bus/usb"
-
-static char *usb_host_device_path;
-
-#define USB_FS_NONE 0
-#define USB_FS_PROC 1
-#define USB_FS_DEV 2
-#define USB_FS_SYS 3
-
-static int usb_fs_type;
 
 /* endpoint association data */
 #define ISO_FRAME_DESC_PER_URB 32
@@ -431,6 +417,31 @@ static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
     }
 }
 
+static int usb_host_open_device(int bus, int addr)
+{
+    const char *usbfs = NULL;
+    char filename[32];
+    struct stat st;
+    int fd, rc;
+
+    rc = stat("/dev/bus/usb", &st);
+    if (rc == 0 && S_ISDIR(st.st_mode)) {
+        /* udev-created device nodes available */
+        usbfs = "/dev/bus/usb";
+    } else {
+        /* fallback: usbfs mounted below /proc */
+        usbfs = "/proc/bus/usb";
+    }
+
+    snprintf(filename, sizeof(filename), "%s/%03d/%03d",
+             usbfs, bus, addr);
+    fd = open(filename, O_RDWR | O_NONBLOCK);
+    if (fd < 0) {
+        fprintf(stderr, "husb: open %s: %s\n", filename, strerror(errno));
+    }
+    return fd;
+}
+
 static int usb_host_claim_port(USBHostDevice *s)
 {
 #ifdef USBDEVFS_CLAIM_PORT
@@ -460,12 +471,7 @@ static int usb_host_claim_port(USBHostDevice *s)
         return -1;
     }
 
-    if (!usb_host_device_path) {
-        return -1;
-    }
-    snprintf(line, sizeof(line), "%s/%03d/%03d",
-             usb_host_device_path, s->match.bus_num, hub_addr);
-    s->hub_fd = open(line, O_RDWR | O_NONBLOCK);
+    s->hub_fd = usb_host_open_device(s->match.bus_num, hub_addr);
     if (s->hub_fd < 0) {
         return -1;
     }
@@ -522,10 +528,6 @@ static int usb_linux_get_num_interfaces(USBHostDevice *s)
     char device_name[64], line[1024];
     int num_interfaces = 0;
 
-    if (usb_fs_type != USB_FS_SYS) {
-        return -1;
-    }
-
     sprintf(device_name, "%d-%s", s->bus_num, s->port);
     if (!usb_host_read_file(line, sizeof(line), "bNumInterfaces",
                             device_name)) {
@@ -1090,41 +1092,21 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
 static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
     uint8_t configuration, uint8_t interface)
 {
-    uint8_t alt_setting;
-    struct usb_ctrltransfer ct;
-    int ret;
-
-    if (usb_fs_type == USB_FS_SYS) {
-        char device_name[64], line[1024];
-        int alt_setting;
+    char device_name[64], line[1024];
+    int alt_setting;
 
-        sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
-                (int)configuration, (int)interface);
+    sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
+            (int)configuration, (int)interface);
 
-        if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
-                                device_name)) {
-            goto usbdevfs;
-        }
-        if (sscanf(line, "%d", &alt_setting) != 1) {
-            goto usbdevfs;
-        }
-        return alt_setting;
-    }
-
-usbdevfs:
-    ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
-    ct.bRequest = USB_REQ_GET_INTERFACE;
-    ct.wValue = 0;
-    ct.wIndex = interface;
-    ct.wLength = 1;
-    ct.data = &alt_setting;
-    ct.timeout = 50;
-    ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
-    if (ret < 0) {
+    if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
+                            device_name)) {
+        /* Assume alt 0 on error */
+        return 0;
+    }
+    if (sscanf(line, "%d", &alt_setting) != 1) {
         /* Assume alt 0 on error */
         return 0;
     }
-
     return alt_setting;
 }
 
@@ -1273,7 +1255,6 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
                          const char *prod_name, int speed)
 {
     int fd = -1, ret;
-    char buf[1024];
 
     trace_usb_host_open_started(bus_num, addr);
 
@@ -1281,15 +1262,8 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
         goto fail;
     }
 
-    if (!usb_host_device_path) {
-        perror("husb: USB Host Device Path not set");
-        goto fail;
-    }
-    snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path,
-             bus_num, addr);
-    fd = open(buf, O_RDWR | O_NONBLOCK);
+    fd = usb_host_open_device(bus_num, addr);
     if (fd < 0) {
-        perror(buf);
         goto fail;
     }
     DPRINTF("husb: opened %s\n", buf);
@@ -1538,149 +1512,6 @@ int usb_host_device_close(const char *devname)
     return -1;
 }
 
-static int get_tag_value(char *buf, int buf_size,
-                         const char *str, const char *tag,
-                         const char *stopchars)
-{
-    const char *p;
-    char *q;
-    p = strstr(str, tag);
-    if (!p) {
-        return -1;
-    }
-    p += strlen(tag);
-    while (qemu_isspace(*p)) {
-        p++;
-    }
-    q = buf;
-    while (*p != '\0' && !strchr(stopchars, *p)) {
-        if ((q - buf) < (buf_size - 1)) {
-            *q++ = *p;
-        }
-        p++;
-    }
-    *q = '\0';
-    return q - buf;
-}
-
-/*
- * Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine
- * host's USB devices. This is legacy support since many distributions
- * are moving to /sys/bus/usb
- */
-static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
-{
-    FILE *f = NULL;
-    char line[1024];
-    char buf[1024];
-    int bus_num, addr, speed, device_count;
-    int class_id, product_id, vendor_id, port;
-    char product_name[512];
-    int ret = 0;
-
-    if (!usb_host_device_path) {
-        perror("husb: USB Host Device Path not set");
-        goto the_end;
-    }
-    snprintf(line, sizeof(line), "%s/devices", usb_host_device_path);
-    f = fopen(line, "r");
-    if (!f) {
-        perror("husb: cannot open devices file");
-        goto the_end;
-    }
-
-    device_count = 0;
-    bus_num = addr = class_id = product_id = vendor_id = port = 0;
-    speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */
-    for(;;) {
-        if (fgets(line, sizeof(line), f) == NULL) {
-            break;
-        }
-        if (strlen(line) > 0) {
-            line[strlen(line) - 1] = '\0';
-        }
-        if (line[0] == 'T' && line[1] == ':') {
-            if (device_count && (vendor_id || product_id)) {
-                /* New device.  Add the previously discovered device.  */
-                if (port > 0) {
-                    snprintf(buf, sizeof(buf), "%d", port);
-                } else {
-                    snprintf(buf, sizeof(buf), "?");
-                }
-                ret = func(opaque, bus_num, addr, buf, class_id, vendor_id,
-                           product_id, product_name, speed);
-                if (ret) {
-                    goto the_end;
-                }
-            }
-            if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0) {
-                goto fail;
-            }
-            bus_num = atoi(buf);
-            if (get_tag_value(buf, sizeof(buf), line, "Port=", " ") < 0) {
-                goto fail;
-            }
-            port = atoi(buf);
-            if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) {
-                goto fail;
-            }
-            addr = atoi(buf);
-            if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
-                goto fail;
-            }
-            if (!strcmp(buf, "5000")) {
-                speed = USB_SPEED_SUPER;
-            } else if (!strcmp(buf, "480")) {
-                speed = USB_SPEED_HIGH;
-            } else if (!strcmp(buf, "1.5")) {
-                speed = USB_SPEED_LOW;
-            } else {
-                speed = USB_SPEED_FULL;
-            }
-            product_name[0] = '\0';
-            class_id = 0xff;
-            device_count++;
-            product_id = 0;
-            vendor_id = 0;
-        } else if (line[0] == 'P' && line[1] == ':') {
-            if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0) {
-                goto fail;
-            }
-            vendor_id = strtoul(buf, NULL, 16);
-            if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0) {
-                goto fail;
-            }
-            product_id = strtoul(buf, NULL, 16);
-        } else if (line[0] == 'S' && line[1] == ':') {
-            if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0) {
-                goto fail;
-            }
-            pstrcpy(product_name, sizeof(product_name), buf);
-        } else if (line[0] == 'D' && line[1] == ':') {
-            if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0) {
-                goto fail;
-            }
-            class_id = strtoul(buf, NULL, 16);
-        }
-    fail: ;
-    }
-    if (device_count && (vendor_id || product_id)) {
-        /* Add the last device.  */
-        if (port > 0) {
-            snprintf(buf, sizeof(buf), "%d", port);
-        } else {
-            snprintf(buf, sizeof(buf), "?");
-        }
-        ret = func(opaque, bus_num, addr, buf, class_id, vendor_id,
-                   product_id, product_name, speed);
-    }
- the_end:
-    if (f) {
-        fclose(f);
-    }
-    return ret;
-}
-
 /*
  * Read sys file-system device file
  *
@@ -1698,7 +1529,7 @@ static int usb_host_read_file(char *line, size_t line_size,
     int ret = 0;
     char filename[PATH_MAX];
 
-    snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/%s", device_name,
+    snprintf(filename, PATH_MAX, "/sys/bus/usb/devices/%s/%s", device_name,
              device_file);
     f = fopen(filename, "r");
     if (f) {
@@ -1716,7 +1547,7 @@ static int usb_host_read_file(char *line, size_t line_size,
  * This code is based on Robert Schiele's original patches posted to
  * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
  */
-static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
+static int usb_host_scan(void *opaque, USBScanFunc *func)
 {
     DIR *dir = NULL;
     char line[1024];
@@ -1726,9 +1557,10 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
     char product_name[512];
     struct dirent *de;
 
-    dir = opendir(USBSYSBUS_PATH "/devices");
+    dir = opendir("/sys/bus/usb/devices");
     if (!dir) {
-        perror("husb: cannot open devices directory");
+        perror("husb: opendir /sys/bus/usb/devices");
+        fprintf(stderr, "husb: please make sure sysfs is mounted at /sys\n");
         goto the_end;
     }
 
@@ -1803,81 +1635,6 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
     return ret;
 }
 
-/*
- * Determine how to access the host's USB devices and call the
- * specific support function.
- */
-static int usb_host_scan(void *opaque, USBScanFunc *func)
-{
-    Monitor *mon = cur_mon;
-    FILE *f = NULL;
-    DIR *dir = NULL;
-    int ret = 0;
-    const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
-    char devpath[PATH_MAX];
-
-    /* only check the host once */
-    if (!usb_fs_type) {
-        dir = opendir(USBSYSBUS_PATH "/devices");
-        if (dir) {
-            /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
-            strcpy(devpath, USBDEVBUS_PATH);
-            usb_fs_type = USB_FS_SYS;
-            closedir(dir);
-            DPRINTF(USBDBG_DEVOPENED, USBSYSBUS_PATH);
-            goto found_devices;
-        }
-        f = fopen(USBPROCBUS_PATH "/devices", "r");
-        if (f) {
-            /* devices found in /proc/bus/usb/ */
-            strcpy(devpath, USBPROCBUS_PATH);
-            usb_fs_type = USB_FS_PROC;
-            fclose(f);
-            DPRINTF(USBDBG_DEVOPENED, USBPROCBUS_PATH);
-            goto found_devices;
-        }
-        /* try additional methods if an access method hasn't been found yet */
-        f = fopen(USBDEVBUS_PATH "/devices", "r");
-        if (f) {
-            /* devices found in /dev/bus/usb/ */
-            strcpy(devpath, USBDEVBUS_PATH);
-            usb_fs_type = USB_FS_DEV;
-            fclose(f);
-            DPRINTF(USBDBG_DEVOPENED, USBDEVBUS_PATH);
-            goto found_devices;
-        }
-    found_devices:
-        if (!usb_fs_type) {
-            if (mon) {
-                monitor_printf(mon, "husb: unable to access USB devices\n");
-            }
-            return -ENOENT;
-        }
-
-        /* the module setting (used later for opening devices) */
-        usb_host_device_path = g_malloc0(strlen(devpath)+1);
-        strcpy(usb_host_device_path, devpath);
-        if (mon) {
-            monitor_printf(mon, "husb: using %s file-system with %s\n",
-                           fs_type[usb_fs_type], usb_host_device_path);
-        }
-    }
-
-    switch (usb_fs_type) {
-    case USB_FS_PROC:
-    case USB_FS_DEV:
-        ret = usb_host_scan_dev(opaque, func);
-        break;
-    case USB_FS_SYS:
-        ret = usb_host_scan_sys(opaque, func);
-        break;
-    default:
-        ret = -EINVAL;
-        break;
-    }
-    return ret;
-}
-
 static QEMUTimer *usb_auto_timer;
 
 static int usb_host_auto_scan(void *opaque, int bus_num,


More information about the Spice-commits mailing list